Screenshot of Xcode project manager when adding the Sign in with Apple capability

At WWDC 2019, Apple introduced Sign in with Apple, a new feature that allows people to sign in or sign up with just a tap using the Apple ID they already have, and skip filling out forms, verifying email addresses, and choosing passwords.

Although it's similar to existing Facebook and Google solutions, Apple does not use Sign In with Apple to profile users or their activity in apps, so it's much more private and secure.

In this tutorial, we'll explore how to add support for Sign in with Apple to your app and allow users to use it to create an account or sign back in, with one tap.

If you'd prefer to jump straight to a demo app, feel free to click here to go to the Conclusion.

Getting started

Note: This tutorial requires Xcode 11 and iOS 13, which are currently in beta, as it relies on new features or frameworks that are not available on previous versions.

Screenshot of Xcode project manager when adding the Sign in with Apple capability

This tutorial is focused on integrating the new Sign in with Apple feature into an existing app, but if you'd like to test Sign in with Apple with a test project, you can create a new project with the "Single View App" template in Xcode.

Sign in with Apple also requires a new entitlement to enable it, or it will fail to work. To enable the capability, navigate to the "Signing & Capabilities" section in the Xcode Project manager, then click "+ Capability" and select "Sign in with Apple".

Also, remember to import Apple's AuthenticationServices framework in your code or this tutorial won't work.

Adding the Sign in with Apple Button

Sign in with Apple button

Next, add the Sign in with Apple button to your app. It's strongly recommended to use the official Sign in with Apple button, as it automatically supports localization and fits well in a variety of places. Also, it will update automatically if Apple changes something in the future.

Adding the Sign in with Apple button is easy and only takes a few lines of code. To handle tap events, add a target with a function that will be called when the user taps the button.

let signInWithAppleButton = ASAuthorizationAppleIDButton(type: .default, style: .black)
signInWithAppleButton.addTarget(self, action: #selector(signInWithAppleButtonTapped), for: .touchUpInside)

You can also customize the button in a variety of ways.

Type

2 Sign in with Apple buttons with different types
let signInWithAppleButton = ASAuthorizationAppleIDButton(type: .default, style: .black)

The button has 3 different types: sign in (.default), sign up (.signUp) and continue (.continue). You should use the appropriate one for your app.

Style

let signInWithAppleButton = ASAuthorizationAppleIDButton(type: .default, style: .black)

There are 3 different styles created to look good on different backgrounds: White (.white), White with Outline Rule (.whiteOutline) and Black (.black). Apple has in depth documentation on when to use each style.

Corner Radius

3 Sign in with Apple buttons with different corner radiuses
signInWithAppleButton.cornerRadius = 10

You can customize the corner radius to match your app's style. The button can be set to any corner radius from the minimum (square) to the maximum (pill shaped).

Sign in with Apple Flow

Preparing to authenticate

Now that you've added the Sign in with Apple button, it's time to implement the Sign in with Apple flow to actually do something when the button is tapped.

The AuthenticationServices framework has something known as 'providers', which support different login types, such as ASAuthorizationPasswordProvider and ASAuthorizationSingleSignOnProvider. Each provider supports creating 'requests', which then initialize an ASAuthorizationController which performs the request and shows whatever UI is needed.

First, create a provider and a request:

let provider = ASAuthorizationAppleIDProvider()
let request = provider.createRequest()

You can set the scopes on the request to ask the user for different types of information, such as their email address or name.

request.requestedScopes = [.fullName, .email]

Next, create an ASAuthorizationController and set your view controller as the delegate and presentation context provider.

let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self

Finally, we need to make the view controller conform to the ASAuthorizationControllerDelegate and ASAuthorizationControllerPresentationContextProviding protocols.

Implementing ASAuthorizationControllerDelegate

This delegate will control the authorization controller and receive a call back when an error occurs or the user authenticates successfully.

First, implement the authorizationController(controller:didCompleteWithError:) method and handle the error appropriately.

func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
    // Handle the error appropriately in your app
}

Then, implement the authorizationController(controller:didCompleteWithAuthorization:) method to handle successful authentications.

The method provides an authorization property that contains a credential variable that is an ASAuthorizationAppleIDCrendential, with the info that the user chose to provide.

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
    guard let credentials = authorization.credential as? ASAuthorizationAppleIDCredential else { return }

    print(credentials.user) // A unique user ID for this account, which will be available after the initial sign in
    print(credentials.realUserStatus) // .likelyReal, .unknown, .unsupported

    print(credentials.fullName) // If the user allowed access to their name, an instance of `PersonNameComponents` containing their first name. Note that Sign in with Apple allows users to change the name that is provided to apps.
    print(credentials.email) // If the user allowed access to their email, a `String` containing it. Note that Sign in with Apple has built in support for obfuscating users' real email address via a random Apple privacy email address.
}

Note that you will not receive user info such as names and emails on sign ins or after the first authentication, so make sure to save the information correctly.

Implementing ASAuthorizationControllerPresentationContextProviding

It isn't required to implement this protocol, but it is strongly recommended to do so. Just provide the current window, like this:

func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
    return view.window ?? UIWindow()
}

This will anchor the Sign in with Apple dialog correctly.

Requesting authentication

After implementing ASAuthorizationController and ASAuthorizationControllerDelegate (and, optionally, ASAuthorizationControllerPresentationContextProviding), you can now ask the controller to perform the request you created.

controller.performRequests()

Performing the Sign in with Apple request shows a Sign in with Apple dialog where the user can select which information to share and sign in.

Verifying returning users

When users sign back in to your app after the initial sign in, or you cache their sign in, you should frequently verify them with Apple that they are still a trusted, legitimate user.

This is made easy by a simple method you can call on the ASAuthorizationAppleIDProvider.

let userID = "000123.00a0b00c0d000e000fgh0ijk0lmn000.1234"

let provider = ASAuthorizationAppleIDProvider()
provider.getCredentialState(forUserID: userID) { (state, error) in
    switch state {
    case .authorized: // The user is authorized
        break
    case .notFound: // The user can't be found
        break
    case .revoked: // Authorization for the given user has been revoked by Apple
        break
    }
}

As you can see, Apple will let you know if the user is still authorized and trusted or if they have been revoked or deleted.

Conclusion

In this tutorial, you learned about adding the Sign in with Apple button to your app and allowing the user to authenticate with their Apple ID.

For your reference, I've created a simple example Xcode Project with a demo app which lets you Sign in with Apple and displays the information received.

Download Materials

I hope this tutorial helped you out and taught you more about Sign in with Apple. If you have any questions or feedback, feel free to send them or email me: [email protected]. Thanks for reading 🔑