Implementing OAuth with ASWebAuthenticationSession
Learn about what OAuth is and how to implement it using ASWebAuthenticationSession. By Felipe Laso-Marsetti.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Implementing OAuth with ASWebAuthenticationSession
30 mins
- Getting Started
- Understanding OAuth
- Authorization Versus Authentication
- OAuth Roles
- The OAuth Flow
- Creating a GitHub App
- User Authorization Settings
- Post Installation Options
- Permissions Settings
- Viewing Your Results
- Connecting GitHub App with ASWebAuthenticationSession
- Updating the Project with GitHub App Values
- Views Overview
- View Models Overview
- Understanding ASWebAuthenticationSession
- Adding ASWebAuthenticationSession
- Checking for Errors
- Setting the Presentation Context Provider
- Starting the Authentication Session
- Handling the Authorization Code
- Displaying the Results
- Understanding Tokens
- Handling Tokens
- How NetworkRequest Handles the Tokens
- Creating Ephemeral Sessions
- Where to Go From Here?
Understanding Tokens
Upon login, users can now acquire an authorization code. This, however, is not the final stopping point. This access code has a very short duration and can usually be used just once. Its purpose is for you to exchange it for an access token and a refresh token.
As you saw earlier, the access token is the one you’ll send with every request to authorize your requests. The refresh token is usually longer-lived. You can use it to acquire a new access token when it expires.
Handling Tokens
With the authorization code in hand, it’s time to exchange it for tokens. You’ll also add logic in your app to handle them properly.
Open NetworkRequest.swift.
Inside start(responseType:completionHandler:)
and right below the following code block:
guard
error == nil,
let data = data
else {
DispatchQueue.main.async {
let error = error ?? NetworkRequest.RequestError.otherError
completionHandler(.failure(error))
}
return
}
Find the line:
if let object = try? JSONDecoder().decode(responseType, from: data) {
Replace this line with the following code:
// 1
if T.self == String.self,
let responseString = String(data: data, encoding: .utf8) {
// 2
let components = responseString.components(separatedBy: "&")
var dictionary: [String: String] = [:]
// 3
for component in components {
let itemComponents = component.components(separatedBy: "=")
if let key = itemComponents.first,
let value = itemComponents.last {
dictionary[key] = value
}
}
// 4
DispatchQueue.main.async {
// 5
NetworkRequest.accessToken = dictionary["access_token"]
NetworkRequest.refreshToken = dictionary["refresh_token"]
completionHandler(.success((response, "Success" as! T)))
}
return
} else if let object = try? JSONDecoder().decode(T.self, from: data) {
Whereas the other GitHub API responses are JSON formatted, the token exchange response comes back as a string. Here’s how you handle that case:
- By adding this statement, you first see if there’s a string response as its contents.
- This response string, with your tokens, is made of key-value pairs separated by the ampersand, which is why you break that string into an array of key-value pairs.
- You loop through each of the components to acquire a Swift dictionary of the response.
- Right now, everything is running in a background thread due to
URLSession
‘s default threading model. Therefore, you make a call toDispatchQueue
to call the next code on the main thread. You need to do this because the completion handler will be updating the UI, which can only be done on the main thread. - The code within the block stores the access and refresh tokens within two helper properties of
NetworkRequest
. It then proceeds to call the completion handler, indicating that the process was successful.
How NetworkRequest Handles the Tokens
To see what NetworkRequest
does with the tokens, switch over to NetworkRequest+User.swift.
These are properties of type String
, but behind the scenes, they read and write the tokens to UserDefaults
so they can persist across app launches.
These tokens are sensitive data, so in your apps, you want to ensure you securely store these in the keychain. This is an interesting topic which you can learn more about here in How To Secure iOS User Data: Keychain Services and Biometrics with SwiftUI.
Build and run. Sign in. While the modal may flash on screen again, you’ll now see the list of your repositories afterward:
Fantastic!
Creating Ephemeral Sessions
The last topic to cover is ephemeral sessions, which are private authentication sessions. Ephemeral sessions don’t cache session-related data to disk but to RAM. Upon session invalidation, the ephemeral sessions’ data clears the session data. This conveniently gives users the added privacy and security.
Open. SignInViewModel.swift. In signInTapped
and below:
authenticationSession.presentationContextProvider = self
Add the following code:
authenticationSession.prefersEphemeralWebBrowserSession = true
This mitigates the issue encountered earlier, where attempting to sign in immediately after running your app a second or third time results in no prompt to enter the user credentials. An ephemeral session means ASWebAuthenticationSession
will not cache anything and will always ask the user for their credentials at the start of the session.
Build and run.
You’ll still be signed in since the app persists the access and refresh tokens. Tap Sign Out at the top to clear the tokens. Now, upon attempting to sign in, you’re asked to input your GitHub username and password. The app won’t cache anything from your previous login, as this is a private session.
Excellent! This might seem like a small issue, but security-wise, it’s of great benefit.
Where to Go From Here?
You can download the completed project by clicking the Download Materials button at the top or bottom of this tutorial.
Great work! In this tutorial, you got an introduction to OAuth and created your own third-party GitHub app using ASWebAuthenticationSession
to authenticate. Some additional features you could try are enhancing the way you store the tokens by putting them in the keychain and adding more GitHub API requests.
If you’re interested in reading more about OAuth, visit IETF’s page, which contains the whole standard. It’ a bit dense, but a good reference.
For ASWebAuthenticationSession
details and documentation, visit the Apple Developer Documentation.
For a comprehensive video course on networking, check out the Networking with URLSession.
If you have any questions or comments, don’t hesitate to reach out in the forum discussion below.