OAuth SSO in iOS Using ASWebAuthenticationSession
This article provides a comprehensive guide on implementing OAuth
single sign-on (SSO) flows in an iOS application using Apple's
ASWebAuthenticationSession API. You will learn how to
configure the authentication session, handle redirects to capture
authorization tokens, and use the
prefersEphemeralWebBrowserSession property to optionally
share or isolate session cookies with the Safari web browser.
Understanding ASWebAuthenticationSession
ASWebAuthenticationSession is the standard Apple
framework used to authenticate a user through a web service, most
commonly for OAuth 2.0 and OpenID Connect flows. It presents a secure,
embedded web view that loads the authentication provider's login page
and listens for a specific callback URL scheme to return the
authentication result to your app.
Step 1: Set Up the Presentation Context
To display the authentication view, your view controller must import
the AuthenticationServices framework and conform to the
ASWebAuthenticationPresentationContextProviding protocol.
This tells the system which window should present the browser
session.
import UIKit
import AuthenticationServices
class LoginViewController: UIViewController, ASWebAuthenticationPresentationContextProviding {
var authSession: ASWebAuthenticationSession?
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return self.view.window ?? ASPresentationAnchor()
}
}Step 2: Initialize the Authentication Session
To start an OAuth flow, you need the authorization URL provided by
your OAuth service and a custom URL scheme registered in your app's
Info.plist (e.g., myapp://).
When the user completes the login on the web page, the OAuth provider
redirects to your custom URL scheme with an authorization code or token
appended as a query parameter. ASWebAuthenticationSession
intercepts this redirect and triggers its completion handler.
func startOAuthFlow() {
guard let authURL = URL(string: "https://example-oauth-provider.com/authorize?client_id=123&redirect_uri=myapp://callback&response_type=code") else {
return
}
let callbackScheme = "myapp"
authSession = ASWebAuthenticationSession(url: authURL, callbackURLScheme: callbackScheme) { callbackURL, error in
if let error = error {
print("Authentication failed: \(error.localizedDescription)")
return
}
guard let callbackURL = callbackURL else { return }
// Extract the authorization code from the callback URL
let queryItems = URLComponents(string: callbackURL.absoluteString)?.queryItems
if let code = queryItems?.first(where: { $0.name == "code" })?.value {
print("Successfully received authorization code: \(code)")
// Proceed to exchange the code for an access token
}
}
authSession?.presentationContextProvider = self
}Step 3: Configure Safari Cookie Sharing
The ability to share session cookies with the Safari browser is
controlled by a single boolean property on the session instance:
prefersEphemeralWebBrowserSession.
Option A: Share Cookies with Safari (Enable SSO)
By default, prefersEphemeralWebBrowserSession is set to
false. When set to false, the session shares
cookies and website data with the user's default Safari browser.
If the user is already logged into the identity provider in Safari, they will not have to enter their credentials again in your app, achieving true single sign-on. Because this accesses shared browser data, iOS will display a system alert asking the user for permission: "App" Wants to Use "domain.com" to Sign In.
// Shares cookies with Safari. Triggers the system permission dialog.
authSession?.prefersEphemeralWebBrowserSession = falseOption B: Do Not Share Cookies (Private Session)
If you set prefersEphemeralWebBrowserSession to
true, the authentication session uses a private, temporary
browser session.
No cookies or data are read from or written to Safari. The user will be forced to enter their login credentials every time, even if they have an active session in Safari. This option bypasses the iOS system permission alert, providing a slightly faster UI transition at the cost of single sign-on convenience.
// Isolates the session. No cookies are shared with Safari.
authSession?.prefersEphemeralWebBrowserSession = trueStep 4: Start the Session
Once you have configured the session and chosen your cookie-sharing
preference, call the start() method to present the web view
to the user.
// Complete implementation inside your login method
authSession?.prefersEphemeralWebBrowserSession = false // Set to true to disable cookie sharing
authSession?.start()Summary of Cookie Behavior
prefersEphemeralWebBrowserSession = false: Uses Safari cookies. Enables seamless SSO across Safari and other apps using the same setting. Displays a system consent alert before opening the web view.prefersEphemeralWebBrowserSession = true: Ignores Safari cookies. Forces a fresh login every time. Does not display the system consent alert. Useful for apps requiring high security or providing a "Log in with a different account" feature.