Is it possible to set a cookie manually using sharedHTTPCookieStorage for a UIWebView?
Asked Answered
P

4

76

I have webviews inside of an iOS application that require an authentication cookie to be properly authenticated. I'm looking for a way to set a cookie inside of an iOS application's webview without having to make an outbound request to set the cookie as I have auth information on the client already.

This post shows us where the UIWebView cookies are stored.

Right now I'm loading a hidden web view to make an outbound request but would prefer not to have to make an external request for setting a simple cookie.

Photoengrave answered 10/5, 2011 at 18:5 Comment(0)
H
140

Yes, you can do this. First, in applicationDidBecomeActive add this line

[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];

The cookieAcceptPolicy is shared across apps and can be changed without your knowledge, so you want to be sure you have the accept policy you need every time your app is running.

Then, to set the cookie:

NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
[cookieProperties setObject:@"testCookie" forKey:NSHTTPCookieName];
[cookieProperties setObject:@"someValue123456" forKey:NSHTTPCookieValue];
[cookieProperties setObject:@"www.example.com" forKey:NSHTTPCookieDomain];
[cookieProperties setObject:@"www.example.com" forKey:NSHTTPCookieOriginURL];
[cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];
[cookieProperties setObject:@"0" forKey:NSHTTPCookieVersion];

// set expiration to one month from now or any NSDate of your choosing
// this makes the cookie sessionless and it will persist across web sessions and app launches
/// if you want the cookie to be destroyed when your app exits, don't set this
[cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];

NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];

This cookie has the name testCookie and value someValue123456 and will be sent with any http request to www.example.com.

For one big caveat to setting cookies, please see my question here!

NSHTTPCookieStorage state not saved on app exit. Any definitive knowledge/documentation out there?

Hesiod answered 10/5, 2011 at 19:8 Comment(7)
NSHTTPCookieStorage certainly does fully implement a persistent cookie storage. It is just a matter of setting the cookie lifetime correctly on the server-side.Wernick
Yes it does implement a persistent cookie storage. Only problem is it fails when the app quits shortly after the cookie is set.Hesiod
Ball, we ended up going with this solution which is pretty close to your answer: lists.apple.com/archives/Webkitsdk-dev/2003/Sep/msg00003.htmlPhotoengrave
@mauvis-ledford how did you assign the created cookie to the uiwebview?Kingpin
A cookie is not associated with a webview, it is associated with an HTTP request to a particular URL. Any HTTP request, whether directly from your code or from a webview will use whatever is stored in NSHTTPCookieStorageHesiod
how to set HttpOnly flag of NSHTTPcookie?Doble
Can someone confirm this still works? I have cookies in NSHTTPCookieStorage, but they don't seem available to the javascript running in my UIWebView. I looked in the cookie store using Safari's web inspector and it's empty. Any help greatly appreciated. iOS 10.3Aha
D
14

Edit: adapting for edited question

NSHTTPCookieStorage has a -setCookies:forURL:mainDocumentURL: method, so the easy thing to do is use NSURLConnection and implement -connection:didReceiveResponse:, extracting cookies and stuffing them into the cookie jar:

- ( void )connection: (NSURLConnection *)connection
          didReceiveResponse: (NSURLResponse *)response
{
    NSHTTPURLResponse        *httpResponse = (NSHTTPURLResponse *)response;
    NSArray                  *cookies;

    cookies = [ NSHTTPCookie cookiesWithResponseHeaderFields:
                             [ httpResponse allHeaderFields ]];
    [[ NSHTTPCookieStorage sharedHTTPCookieStorage ]
            setCookies: cookies forURL: self.url mainDocumentURL: nil ];
}

(You can also simply extract an NSDictionary object from the NSHTTPCookie with properties, and then write the dictionary to the disk. Reading it back in is as easy as using NSDictionary's -dictionaryWithContentsOfFile: and then creating the cookie with -initWithProperties:.)

Then you can pull the cookie back out of the storage when you need it:

- ( void )reloadWebview: (id)sender
{
    NSArray                 *cookies;
    NSDictionary            *cookieHeaders;
    NSMutableURLRequest     *request;

    cookies = [[ NSHTTPCookieStorage sharedHTTPCookieStorage ]
                cookiesForURL: self.url ];
    if ( !cookies ) {
        /* kick off new NSURLConnection to retrieve new auth cookie */
        return;
    }

    cookieHeaders = [ NSHTTPCookie requestHeaderFieldsWithCookies: cookies ];
    request = [[ NSMutableURLRequest alloc ] initWithURL: self.url ];
    [ request setValue: [ cookieHeaders objectForKey: @"Cookie" ]
              forHTTPHeaderField: @"Cookie" ];

    [ self.webView loadRequest: request ];
    [ request release ];
}
Detinue answered 10/5, 2011 at 19:1 Comment(3)
There is no need to manually manage NSHTTPCookieStorage this way. Any time the URL loading system is using HTTP and the cookie accept policy is set to accept cookies, NSHTTPCookieStorage is managed automatically - storing cookies if set in response headers, and setting headers for stored cookies when sending requests.Hesiod
Sure. Of course, that approach means the developer is ignorant of what cookies are saved and sent with each request, which can be undesirable if, say, the site is setting unwanted tracking cookies. Using NSHTTPCookieStorage at all can be a heavyweight solution, too, though typically only on Mac OS X. For example, see: cocoabuilder.com/archive/cocoa/…Detinue
Appreciate the long answer, though it seems to be a considerable amount of work to set a single cookie. We ended up doing this: lists.apple.com/archives/Webkitsdk-dev/2003/Sep/msg00003.htmlPhotoengrave
T
8

In Swift 3 all of the keys are wrapped in the HTTPCookiePropertyKey struct:

let cookieProperties: [HTTPCookiePropertyKey : Any] = [.name : "name",
                                                       .value : "value",
                                                       .domain : "www.example.com",
                                                       .originURL : "www.example.com",
                                                       .path : "/",
                                                       .version : "0",
                                                       .expires : Date().addingTimeInterval(2629743)
                                                      ]

if let cookie = HTTPCookie(properties: cookieProperties) {
    HTTPCookieStorage.shared.setCookie(cookie)
}
Taliesin answered 25/4, 2017 at 17:15 Comment(1)
thanks, i was providing a URL object not a string to domain and originURL Expatriate
P
1

There is need to work around the limitations on cookies introduced by iOS 10, which makes them invisible to different processes.

This means that on devices with multiprocessing capability, webviews are a distinct process then your app, which means your "app" session is not transmitted automatically to the webview anymore.

So in essense, you will need to do it (even is previous posters where right, it was working automatically before iOS10).

Portaltoportal answered 24/11, 2016 at 13:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.