3

tl;dr read the last paragraph.

I am using AppAuth (https://github.com/openid/AppAuth-iOS) library for handling OpenID based authentication of users for which I want to provide SSO experience through my app. The deployment target of my app is iOS 11 which means AppAuth internally uses SFAuthenticationSession. I am using authorization flow, which means the user is presented with a web based login page via SFAuthenticationSession. When a user fills in and submits the credentials SFAuthenticationSession calls completion with url (if successful) from which authorization code can be parsed. With the authorization code a token POST request through URLSession is made independently of SFAuthenticationSession and the access_token is retrieved.

The entire flow is successful including the retrieval of access_token, but when I leave the app and open user's profile webpage provided by the service provider in Safari the user is not logged in. I have tested the same flow with a Google account (https://accounts.google.com) and SSO worked fine, e.g. when I opened https://mail.google.com in Safari I was logged in. So I have a suspicion my service provider is doing something wrong. Perhaps they didn't supply me with correct scopes? But before contacting them I want to rule out any fault of mine. Now my most immediate thought is that somehow the session related cookies do not get stored in Safari. From this my question follows.

My question. Token POST request is made independently of SFAuthenticationSession (different user agent) so how any session related cookies get stored on the device (Safari) if not through SFAuthenticationSession? And is there any way to debug cookie storage in code?

Au Ris
  • 4,541
  • 2
  • 26
  • 53
  • Check if cookies has expiration date. You can use wkwebview to see cookies. if no expiration date, all apple os devices will automatically set cookies as one session cookie. If you have MacBook open your url in Safari and logIn, then close Safari. Now open Safari, open url again, and see if you still logged in. – canister_exister Dec 07 '18 at 15:11

3 Answers3

4

According to the OAuth 2.0 standard, the token endpoint does not require the resource owner authentication, as an opposite to the authorization endpoint, which does. (A script or a back-channel performing authorization code exchange does not necessarily have access to HTTP cookies set in the user agent and, by default, browsers do not include credentials in cross-site XHRs. When a refresh token is used the resource owner interaction is not needed at all.) Your URLSession does not get any session cookie from Safari or SFAuthenticationSession and should not need one.

As for your mobile Safari experience, docs for ASWebAuthenticationSession, the SFAuthenticationSession successor, state:

All cookies, except session cookies, can be shared with Safari.

It seems to be the case for SFAuthenticationSession as well. Google must be using persistent cookies, and as a result session sharing works with them.

On a side note, even with persistent cookies there appears to be some inconsistency in syncing the cookie jars in iOS 11 environment, for example: http://www.openradar.me/radar?id=5036182937272320

Community
  • 1
  • 1
ko la
  • 431
  • 4
  • 9
1

To debug cookies you can use this code:

import UIKit

import WebKit

class ViewController: UIViewController, WKNavigationDelegate {

var webView: WKWebView?

override func viewDidLoad() {
    super.viewDidLoad()

    let configuration = WKWebViewConfiguration()
    webView = WKWebView(frame: .zero,configuration:configuration)
    self.view = webView
}

override func viewDidAppear(_ animated: Bool) {
    let url = URL(string: "YOUR URL")

    let request = URLRequest(url: url!)

    webView?.navigationDelegate = self
    webView?.addObserver(self, forKeyPath: "URL", options: [.new, .old], context: nil)

    self.webView?.load(request)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

    if let newValue = change?[.newKey] as? Int, let oldValue = change?[.oldKey] as? Int, newValue != oldValue {

        print("NEW",change?[.newKey])
    } else {
        print("OLD",change?[.oldKey])

    }

    webView?.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in
        for cookie in cookies {
            print(cookie)
        }
    }
}
}

And check if cookies has expiresDate property. If not you will not able use SSO.

Kerberos
  • 4,036
  • 3
  • 36
  • 55
canister_exister
  • 567
  • 4
  • 15
  • 1
    Thanks for your answer, but this does not look like what I need. UIWebView has its own cookie store and does not share cookies with Safari. My question concerns SSO and sharing cookies with Safari browser. – Au Ris Dec 10 '18 at 09:58
  • I understand what you need, this answer just to debug cookies for session. How I already said you can check cookie expiration date using this method. WKWebView is the only way you can debug session cookie. Safari, SFAuthenticationSession, SFSafariViewController, ASWebAuthenticationSession not allow to debug cookies. – canister_exister Dec 10 '18 at 14:39
  • 1
    Thanks. I appreciate your answer. – Au Ris Dec 11 '18 at 08:59
0

If you wanted to not store the cookies in the browser, you could do auth via a private browsing session with ASWebAuthenticationSession with prefersEphemeralWebBrowserSession set to true.

https://github.com/openid/AppAuth-iOS/issues/530#issuecomment-628159766

t.ios
  • 1,024
  • 12
  • 18