iOS Swift - Sign In With Apple

View on Github

iOS Swift - Sign In With Apple

Gravatar for
By Martin Walsh

This tutorial demonstrates how to add user login to a Swift application using Sign In With Apple. We recommend that you log in to follow this quickstart with examples configured for your account.

I want to explore a sample app

2 minutes

Get a sample configured with your account settings or check it out on Github.

View on Github
System requirements: CocoaPods | Xcode 11 Beta 6 | iOS 13 Beta 8 Device

Before You Start

This tutorial describes how to implement the native Sign In With Apple introduced in iOS 13. Alternatively, check out the iOS Swift Login tutorial for Web Authentication with Auth0.

Before you start, you'll need:

New to Auth? Learn How Auth0 works, how it integrates with Native Applications and which protocol it uses.

Configure Auth0

Get Your Application Keys

When you signed up for Auth0, a new application was created for you, or you could have created a new one. You will need some details about that application to communicate with Auth0. You can get these details from the Application Settings section in the Auth0 dashboard.

App Dashboard

When using the Default App with a Native or Single Page Application, ensure to update the Token Endpoint Authentication Method to None and set the Application Type to either SPA or Native.

You need the following information:

  • Domain
  • Client ID

If you download the sample from the top of this page, these details are filled out for you.

Add your credentials in the Auth0.plist file. If the file does not exist in your project yet, create one with the information below (Apple documentation on Property List Files):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">

Install Dependencies


If you are using Cocoapods, add this line to your Podfile:

pod 'Auth0', '~> 1.0'

Then run pod install.

For more information on Cocoapods, check their official documentation.


If you are using Carthage, add the following line to your Cartfile:

github "auth0/Auth0.swift" ~> 1.0

Then run carthage bootstrap.

For more information about Carthage usage, check their official documentation.


If you are using the Swift Package Manager, open the following menu item in Xcode:

File > Swift Packages > Add Package Dependency...

In the Choose Package Repository prompt add this url:

Then press Next and complete the remaining steps.

For further reference on SPM, check its official documentation.

Add the "Sign In With Apple" Button

As an example of adding the sign-in button to your view, add a UIStackView to your main storyboard and create an outlet in ViewController.swift:

 @IBOutlet weak var loginProviderStackView: UIStackView!

Next, add the AuthenticationServices Framework to your ViewController.swift:

import AuthenticationServices

Add a function that attaches an ASAuthorizationAppleIDButton button to the stack view:

func setupProviderLoginView() {
  // Create Button
  let authorizationButton = ASAuthorizationAppleIDButton()

  // Add Callback on Touch
  authorizationButton.addTarget(self, action: #selector(handleAuthorizationAppleIDButtonPress), for: .touchUpInside)

  // Add button to the UIStackView

Call this function in viewDidLoad:

override func viewDidLoad() {


Handle Authorization

The following code shows the implementation of a button handler that initializes an authorization request and launches the native Sign In With Apple flow:

func handleAuthorizationAppleIDButtonPress() {
    // Create the authorization request
    let request = ASAuthorizationAppleIDProvider().createRequest()

    // Set scopes
    request.requestedScopes = [.email, .fullName]

    // Setup a controller to display the authorization flow
    let controller = ASAuthorizationController(authorizationRequests: [request])

    // Set delegates to handle the flow response.
    controller.delegate = self
    controller.presentationContextProvider = self

    // Action

At this time the only scopes that Apple support are email and fullName. For more information, see ASAuthorization.scope.

At this point, you will have a few compile errors to deal with. Before moving forward with all the code, let's remove those errors by providing some basic delegates.

Add authorization extensions

Add the following to the end of the ViewController.swift file. This enables the authorization flow UI to be displayed from the controller:

extension ViewController: ASAuthorizationControllerPresentationContextProviding {
    func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        return view.window!

Next, add a stub delegate for the ASAuthorizationController to the end of the ViewController.swift file. This code will handle the response sent to the ASAuthorizationController. You will come back to this one later.

extension ViewController: ASAuthorizationControllerDelegate {


Add the Sign in with Apple capability

To enable Sign In With Apple in your application, you need to enable this capability to your app, as shown:

Add capabilities


Start the application and click the Sign In With Apple button. You should see the default sign-in dialog appear:

Default sign-in dialog

Process the Authorization Response

Add the following methods to the ASAuthorizationControllerDelegate delegate stub at the end of your ViewController.swift file.

extension ViewController: ASAuthorizationControllerDelegate {
    // Handle authorization success
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
            // Success

    // Handle authorization failure
    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        print("Authorization Failed: \(error)")

Inspect the response

Upon successful authorization, you will be able to access the following information:

  • UUID, team-scoped user ID
  • Verification Data
    • ID Token, Authorization Code
  • Account Information
    • Name, Verified Email Address (Original or relay address)
  • Real user indicator
    • High confidence indicator that the user is who they say they are

The Account Information is ONLY sent on the first successful authorization. This information should be saved by your app if you wish to use it when a user leaves and reloads your application.

Auth0 Token Exchange

Now that you have a successful authorization response, you can use the authorizationCode and fullName to perform a token exchange. The token exchange will give you access to Auth0 credentials, such as the ID and Access Tokens. For example:

if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
    // Convert Data -> String
    guard let authorizationCode = appleIDCredential.authorizationCode,
        let authCode = String(data: authorizationCode, encoding: .utf8) else {
            print("Problem with the authorizationCode")

    // Auth0 Token Exchange
        .login(appleAuthorizationCode: authCode, fullName: appleIDCredential.fullName).start { result in
            switch result {
            case .success(let credentials):
                print("Auth0 Success: \(credentials)")
            case .failure(let error):
                print("Exchange Failed: \(error)")

Auth0 requires the fullName parameter to complete the user profile with properties like the first and last name, because the ID Token obtained from Apple does not include that information.

Renew Authentication

When users return to your app, you can log them in automatically if their login session is still valid. This involves:

  • Calling ASAuthorizationAppleIDProvider.getCredentialState to make sure the user is still authorized
  • Retrieving Auth0 credentials

To do this, you're going to:

  • Use CredentialsManager to store the Auth0 credentials
  • Use SimpleKeychain to store the Apple user ID
  • Check the credential state using Apple's APIs before retrieving Auth0 credentials

Store credentials

The credentials manager retrieves stored credentials from the keychain and checks if the Access Token is still valid:

  • If the current credentials are still valid, the credentials manager returns them
  • If the Access Token has expired, the credentials manager renews them using the Refresh Token and returns them

First, import the SimpleKeychain Framework into your ViewController.swift file:

import SimpleKeychain

Then, add a CredentialsManager and SimpleKeychain instance as follows:

let credentialsManager = CredentialsManager(authentication: Auth0.authentication())
let keychain = A0SimpleKeychain()

// Add a place to store credentials locally once they're renewed
var credentials: Credentials?

Next, modify the token exchange call you added earlier to store credentials when the user logs in:

    .login(appleAuthorizationCode: authCode, fullName: appleIDCredential.fullName).start { result in
        switch result {
        case .success(let credentials):
            // NEW - store the user ID in the keychain
            self.keychain.setString(appleIDCredential.user, forKey: "userId")

            // NEW - store the credentials locally
            self.credentials = credentials

            // NEW - store the credentials in the credentials manager
        case .failure(let error):
            print("Exchange Failed: \(error)")

Renew authentication state

Add a function that tries to renew the user's login session. Here, getCredentialState is called to find out whether the user is still authorized for Sign In With Apple. If they are unauthorized, you should consider their access revoked, their access and refresh tokens should be removed, and the user should log into the application again. Otherwise, the credentials that were previously stored inside CredentialsManager can be returned, as in the following example:

func tryRenewAuth(_ callback: @escaping (Credentials?, Error?) -> ()) {
    let provider = ASAuthorizationAppleIDProvider()

    // Try to fetch the user ID
    guard let userID = keychain.string(forKey: "userId") else {
        return callback(nil, nil)

    // Check the Apple credential state
    provider.getCredentialState(forUserID: userID) { state, error in
        switch state {
        case .authorized:
            // Try to get credentials from the creds manager (ID token, Access Token, etc)
            self.credentialsManager.credentials { error, credentials in
                guard error == nil, let credentials = credentials else {
                    return callback(nil, error)

                self.credentials = credentials

                callback(credentials, nil)
            // User is not authorized
            self.keychain.deleteEntry(forKey: "userId")

            // Remove their credentials from the store

            callback(nil, error)

Calling credentialsManager.credentials automatically renews the Access Token if it has expired, using the refresh token. This call should only be executed if getCredentialState returns authorized, so that the refresh token is only used by an authorized user. Otherwise, the credentials must be cleared and the login session thrown away.

Finally, call this function from viewDidLoad. If no credentials are found, the user should be shown the login screen once more. Otherwise, they should continue on into the app:

tryRenewAuth { credentials, error in
    guard error == nil, credentials != nil else {
        print("Unable to renew auth: \(String(describing: error))")

        // The user should be asked to log in again


    // Set up any post-login UI or segue here

Next Steps

Now that you're able to use Sign In With Apple and exchange the authorization code for Auth0 credentials, you can use these credentials to perform various tasks:

Use Auth0 for FREE