IPhone: NSHTTPCookie not saved through application reloads

In my iPhone application, I want to be able to reuse the same server-side session when my application restarts. A session on the server is identified by a cookie, which is sent for each request. When I restart the application, this cookie disappeared and I can no longer use the same session.

What I noticed when I used NSHTTPCookieStorage to search for cookies received from the server is that [cookie isSessionOnly] returns YES . I get the impression that this is why cookies are not saved in reboots of my application. What do I need to do to make my cookie NOT a session? What HTTP headers do I need to send from the server?

+30
iphone cookies
Apr 18 2018-10-18T00:
source share
7 answers

You can save a cookie by saving its property dictionary and then restoring it as a new cookie before proceeding to reconnect.

Save

 NSArray* allCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:URL]]; for (NSHTTPCookie *cookie in allCookies) { if ([cookie.name isEqualToString:MY_COOKIE]) { NSMutableDictionary* cookieDictionary = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey:PREF_KEY]]; [cookieDictionary setValue:cookie.properties forKey:URL]; [[NSUserDefaults standardUserDefaults] setObject:cookieDictionary forKey:PREF_KEY]; } } 

Load:

 NSDictionary* cookieDictionary = [[NSUserDefaults standardUserDefaults] dictionaryForKey:PREF_KEY]; NSDictionary* cookieProperties = [cookieDictionary valueForKey:URL]; if (cookieProperties != nil) { NSHTTPCookie* cookie = [NSHTTPCookie cookieWithProperties:cookieProperties]; NSArray* cookieArray = [NSArray arrayWithObject:cookie]; [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookieArray forURL:[NSURL URLWithString:URL] mainDocumentURL:nil]; } 
+44
May 09 '11 at 03:17
source

I have an upvoted @TomIrving answer and I am here because many users will not see a very important comment in which he says:

"You need to set an expiration date, otherwise the cookie will be considered a session."

In principle, the cookie will be deleted when the application is closed, if in the future the cookie has an expiration date.

You do not need to store and restore cookies in NSUserDefaults and NSUserDefaults if you have control over the server and you can ask it to point the β€œExpires” header to something in the future. If you do not have control over the server or do not want to redefine the behavior of your server, you can "trick" your application by changing the expiresDate inside it:

When you reopen the application, you will notice that the cookie has not been deleted.

+23
Apr 14 '14 at 12:25
source

Session-only cookies expire in nature. You can save them manually in Keychain if you really want to. I prefer Keychain to be stored in UserDefaults or archived because cookies are better protected, as is the user's password.

Unfortunately, saving cookies only for the session is not very useful, the code below is just an illustration of how to store cookies, but cannot force the server to accept such cookies in any way (unless you can control the server).

Swift 2.2

 // Saving into Keychain if let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies { let cookiesData: NSData = NSKeyedArchiver.archivedDataWithRootObject(cookies) let userAccount = "some unique string to identify the item in Keychain, in my case I use username" let domain = "some other string you can use in combination with userAccount to identify the item" let keychainQuery: [NSString: NSObject] = [ kSecClass: kSecClassGenericPassword, kSecAttrAccount: userAccount + "cookies", kSecAttrService: domain, kSecValueData: cookiesData] SecItemDelete(keychainQuery as CFDictionaryRef) //Trying to delete the item from Keychaing just in case it already exists there let status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil) if (status == errSecSuccess) { print("Cookies succesfully saved into Keychain") } } // Getting from Keychain let userAccount = "some unique string to identify the item in Keychain, in my case I use username" let domain = "some other string you can use in combination with userAccount to identify the item" let keychainQueryForCookies: [NSString: NSObject] = [ kSecClass: kSecClassGenericPassword, kSecAttrService: domain, // we use JIRA URL as service string for Keychain kSecAttrAccount: userAccount + "cookies", kSecReturnData: kCFBooleanTrue, kSecMatchLimit: kSecMatchLimitOne] var rawResultForCookies: AnyObject? let status: OSStatus = SecItemCopyMatching(keychainQueryForCookies, &rawResultForCookies) if (status == errSecSuccess) { let retrievedData = rawResultForCookies as? NSData if let unwrappedData = retrievedData { if let cookies = NSKeyedUnarchiver.unarchiveObjectWithData(unwrappedData) as? [NSHTTPCookie] { for aCookie in cookies { NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(aCookie) } } } } 
+5
Jul 23 '16 at 17:21
source

I believe that the server before deciding whether a cookie is only a session, you can not do anything about it.

+3
Apr 18 2018-10-18T00:
source

Quick way

Store:

 static func storeCookies() { let cookiesStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage() let userDefaults = NSUserDefaults.standardUserDefaults() let serverBaseUrl = "http://yourserverurl.com" var cookieDict = [String : AnyObject]() for cookie in cookiesStorage.cookiesForURL(NSURL(string: serverBaseUrl)!)! { cookieDict[cookie.name] = cookie.properties } userDefaults.setObject(cookieDict, forKey: cookiesKey) } 

Recovery:

 static func restoreCookies() { let cookiesStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage() let userDefaults = NSUserDefaults.standardUserDefaults() if let cookieDictionary = userDefaults.dictionaryForKey(cookiesKey) { for (cookieName, cookieProperties) in cookieDictionary { if let cookie = NSHTTPCookie(properties: cookieProperties as! [String : AnyObject] ) { cookiesStorage.setCookie(cookie) } } } } 
+1
Jan 27 '16 at 9:05
source

SWIFT 3

SAVE:

 if let httpResponse = response as? HTTPURLResponse, let fields = httpResponse.allHeaderFields as? [String : String] { let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields, for: response.url!) HTTPCookieStorage.shared.setCookies(cookies, for: response.url!, mainDocumentURL: nil) for cookie in cookies { if cookie.name == cookieName{ if cookieName == Constants.WS.COOKIES.COOKIE_SMS { UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: cookie), forKey: Constants.SHARED_DEFAULT.COOKIE_SMS) UserDefaults.standard.synchronize() } return cookie.value } } } 

Get

 let cookie: HTTPCookie = NSKeyedUnarchiver.unarchiveObject(with: UserDefaults.standard.object(forKey: Constants.SHARED_DEFAULT.COOKIE_SMS) as! Data) as! HTTPCookie HTTPCookieStorage.shared.setCookie(cookie) 
0
Oct 10 '16 at 14:20
source

Swift 5 Version

 func storeCookies() { guard let serverBaseUrl = URL(string: Constants.baseURL) else { return } let cookiesStorage: HTTPCookieStorage = .shared var cookieDict: [String: Any] = [:] cookiesStorage.cookies(for: serverBaseUrl)?.forEach({ cookieDict[$0.name] = $0.properties }) let userDefaults = UserDefaults.standard userDefaults.set(cookieDict, forKey: Constants.cookiesKey) } func restoreCookies() { let cookiesStorage: HTTPCookieStorage = .shared let userDefaults = UserDefaults.standard guard let cookieDictionary = userDefaults.dictionary(forKey: Constants.cookiesKey) else { return } let cookies = cookieDictionary .compactMap({ $0.value as? [HTTPCookiePropertyKey: Any] }) .compactMap({ HTTPCookie(properties: $0) }) cookiesStorage.setCookies(cookies, for: URL(string: Constants.baseURL), mainDocumentURL: nil) } 
0
Aug 30 '19 at 13:07 on
source



All Articles