Implementing User Authentication with Sign in with Apple

Overview

Implementing User Authentication with Sign in with Apple

Provide a way for users of your app to set up an account and start using your services.

Overview

This sample app, Juice, uses the AuthenticationServices framework to provide users an interface to set up accounts and sign in with their Apple ID. The app presents a form in which the user can create and set up an account for the app, then authenticates the user’s Apple ID with Sign in with Apple, and displays the user’s account data.

For more information about implementing Sign in with Apple on iOS 12 and earlier, see Incorporating Sign in with Apple into Other Platforms.

Configure the Sample Code Project

To configure the sample code project, perform the following steps in Xcode:

  1. On the Signing & Capabilities pane, set the bundle ID to a unique identifier (you must change the bundle ID to proceed).
  2. Add your Apple ID account and assign the target to a team so Xcode can enable the Sign in with Apple capability with your provisioning profile.
  3. Choose a run destination from the scheme pop-up menu that you’re signed into with an Apple ID and that uses Two-Factor Authentication.
  4. If necessary, click Register Device in the Signing & Capabilities pane to create the provisioning profile.
  5. In the toolbar, click Run, or choose Product > Run (⌘R).

Add a Sign in with Apple Button

In the sample app, LoginViewController displays a login form and a Sign in with Apple button (ASAuthorizationAppleIDButton) in its view hierarchy. The view controller also adds itself as the button’s target, and passes an action to be invoked when the button receives a touch-up event.

func setupProviderLoginView() {
    let authorizationButton = ASAuthorizationAppleIDButton()
    authorizationButton.addTarget(self, action: #selector(handleAuthorizationAppleIDButtonPress), for: .touchUpInside)
    self.loginProviderStackView.addArrangedSubview(authorizationButton)
}

View in Source

  • Important: When adding the Sign in with Apple button to your storyboard, you must also set the control's class value to ASAuthorizationAppleIDButton in Xcode's Identity Inspector.

Request Authorization with Apple ID

When the user taps the Sign in with Apple button, the view controller invokes the handleAuthorizationAppleIDButtonPress() function, which starts the authentication flow by performing an authorization request for the users’s full name and email address. The system then checks whether the user is signed in with their Apple ID on the device. If the user is not signed in at the system-level, the app presents an alert directing the user to sign in with their Apple ID in Settings.

@objc
func handleAuthorizationAppleIDButtonPress() {
    let appleIDProvider = ASAuthorizationAppleIDProvider()
    let request = appleIDProvider.createRequest()
    request.requestedScopes = [.fullName, .email]
    
    let authorizationController = ASAuthorizationController(authorizationRequests: [request])
    authorizationController.delegate = self
    authorizationController.presentationContextProvider = self
    authorizationController.performRequests()
}

View in Source

  • Important: The user must enable Two-Factor Authentication to use Sign in with Apple so that access to the account is secure.

The authorization controller calls the ASAuthorizationControllerPresentationContextProviding.presentationAnchor(for:) function to get the window from the app where it presents the Sign in with Apple content to the user in a modal sheet.

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

View in Source

If the user is signed in at the system-level with their Apple ID, the sheet appears describing the Sign in with Apple feature, followed by another sheet allowing the user to edit the information in their account. The user can edit their first and last name, choose another email address as their contact information, and hide their email address from the app. If the user chooses to hide their email address from the app, Apple generates a proxy email address to forward email to the user’s private email address. Lastly, the user enters the password for the Apple ID, then clicks Continue to create the account.

Handle User Credentials

If the authentication succeeds, the authorization controller invokes the ASAuthorizationControllerDelegate.authorizationController(controller:didCompleteWithAuthorization:) delegate function, which the app uses to store the user’s data in the keychain.

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
    switch authorization.credential {
    case let appleIDCredential as ASAuthorizationAppleIDCredential:
        
        // Create an account in your system.
        let userIdentifier = appleIDCredential.user
        let fullName = appleIDCredential.fullName
        let email = appleIDCredential.email
        
        // For the purpose of this demo app, store the `userIdentifier` in the keychain.
        self.saveUserInKeychain(userIdentifier)
        
        // For the purpose of this demo app, show the Apple ID credential information in the `ResultViewController`.
        self.showResultViewController(userIdentifier: userIdentifier, fullName: fullName, email: email)
    
    case let passwordCredential as ASPasswordCredential:
    
        // Sign in using an existing iCloud Keychain credential.
        let username = passwordCredential.user
        let password = passwordCredential.password
        
        // For the purpose of this demo app, show the password credential as an alert.
        DispatchQueue.main.async {
            self.showPasswordCredentialAlert(username: username, password: password)
        }
        
    default:
        break
    }
}

View in Source

  • Note: In your implementation, the ASAuthorizationControllerDelegate.authorizationController(controller:didCompleteWithAuthorization:) delegate function should create an account in your system using the data contained in the user identifier.

If the authentication fails, the authorization controller invokes the ASAuthorizationControllerDelegate.authorizationController(controller:didCompleteWithError:) delegate function to handle the error.

func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
    // Handle error.
}

View in Source

Once the system authenticates the user, the app displays the ResultViewController which shows the user information requested from the framework, including the user-provided full name and email address. The view controller also displays a Sign Out button and stores the user data in the keychain. When the user taps the Sign Out button, the app deletes the user information from the view controller and the keychain, and presents the LoginViewController to the user.

Request Existing Credentials

The LoginViewController.performExistingAccountSetupFlows() function checks if the user has an existing account by requesting both an Apple ID and an iCloud keychain password. Similar to handleAuthorizationAppleIDButtonPress(), the authorization controller sets its presentation content provider and delegate to the LoginViewController object.

func performExistingAccountSetupFlows() {
    // Prepare requests for both Apple ID and password providers.
    let requests = [ASAuthorizationAppleIDProvider().createRequest(),
                    ASAuthorizationPasswordProvider().createRequest()]
    
    // Create an authorization controller with the given requests.
    let authorizationController = ASAuthorizationController(authorizationRequests: requests)
    authorizationController.delegate = self
    authorizationController.presentationContextProvider = self
    authorizationController.performRequests()
}

View in Source

The authorizationController(controller:didCompleteWithAuthorization:) delegate function checks whether the credential is an Apple ID (ASAuthorizationAppleIDCredential) or a password credential (ASPasswordCredential). If the credential is a password credential, the system displays an alert allowing the user to authenticate with the existing account.

Check User Credentials at Launch

The sample app only shows the Sign in with Apple user interface when necessary. The app delegate checks the status of the saved user credentials immediately after launch in the AppDelegate.application(_:didFinishLaunchingWithOptions:) function.

The ASAuthorizationAppleIDProvider.getCredentialState() function retrieves the state of the user identifier saved in the keychain. If the user granted authorization for the app (for example, the user is signed into the app with their Apple ID on the device), then the app continues executing. If the user revoked authorization for the app, or the user’s credential state not found, the app displays the log in form by invoking the showLoginViewController() function.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let appleIDProvider = ASAuthorizationAppleIDProvider()
    appleIDProvider.getCredentialState(forUserID: KeychainItem.currentUserIdentifier) { (credentialState, error) in
        switch credentialState {
        case .authorized:
            break // The Apple ID credential is valid.
        case .revoked, .notFound:
            // The Apple ID credential is either revoked or was not found, so show the sign-in UI.
            DispatchQueue.main.async {
                self.window?.rootViewController?.showLoginViewController()
            }
        default:
            break
        }
    }
    return true
}

View in Source

You might also like...
Rock - Paper - Scissors game. CPU gives you a sign and asks to win or lose your move. Than you have to decide witch sign do you choose to score a point
Rock - Paper - Scissors game. CPU gives you a sign and asks to win or lose your move. Than you have to decide witch sign do you choose to score a point

RockPaperScissors 2nd challange from HackingWithSwift.com. The CPU gives you a sign (rock, paper or scissors) and asks you either to win or to lose th

Completed Project for Authentication in SwiftUI using Firebase Auth SDK & Sign in with Apple
Completed Project for Authentication in SwiftUI using Firebase Auth SDK & Sign in with Apple

Completed Project for Authentication in SwiftUI using Firebase Auth SDK & Sign in with Apple Follow the tutorial at alfianlosari.com Features Uses Fir

Save data to the database, real-time synchronization, user authentication.

Shop List App on development stage... description description description description description 🛡️ License This project is licensed under the MIT L

Custom MacBook login screen and pam modules using multipeer connectivity and usb hardware checks with iOS app for sign in.

Custom MacBook login screen and pam modules using multipeer connectivity and usb hardware checks with iOS app for sign in.

RSA public/private key generation, RSA, AES encryption/decryption, RSA sign/verify in Swift with CommonCrypto in iOS and OS X

SwCrypt Create public and private RSA keys in DER format let (privateKey, publicKey) = try! CC.RSA.generateKeyPair(2048) Convert them to PEM format l

How to build and sign your iOS application using Azure DevOps

How to build and sign your iOS application using Azure DevOps Sample source code

A passcode entry field for macOS similar to Apple's two-factor authentication field.
A passcode entry field for macOS similar to Apple's two-factor authentication field.

DSFPasscodeView A passcode entry field for macOS similar to Apple's two-factor authentication field. About The control is made up of multiple groups o

Use Apple FaceID or TouchID authentication in your app using BiometricAuthentication.
Use Apple FaceID or TouchID authentication in your app using BiometricAuthentication.

BiometricAuthentication Use Apple FaceID or TouchID authentication in your app using BiometricAuthentication. It's very simple and easy to use that ha

Display Apple system-like self-hiding status alerts. It is well suited for notifying user without interrupting user flow in iOS-like way.
Display Apple system-like self-hiding status alerts. It is well suited for notifying user without interrupting user flow in iOS-like way.

StatusAlert is being sponsored by the following tool; please help to support us by takin a look and signing up to a free trial. Dependency managers Fe

TopicEventBus is Easy to use, type safe way of implementing Publish–subscribe design pattern.
TopicEventBus is Easy to use, type safe way of implementing Publish–subscribe design pattern.

TopicEventBus Publish–subscribe design pattern implementation framework, with ability to publish events by topic. (NotificationCenter extended alterna

FluxCapacitor makes implementing Flux design pattern easily with protocols and typealias.
FluxCapacitor makes implementing Flux design pattern easily with protocols and typealias.

FluxCapacitor makes implementing Flux design pattern easily with protocols and typealias. Storable protocol Actionable protocol Dispatch

CodeEditorView Swift package provides a SwiftUI view implementing a rich code editor for iOS and macOS Easy to use UITableViewCell implementing swiping to trigger actions.
Easy to use UITableViewCell implementing swiping to trigger actions.

SwipyCell Swipeable UITableViewCell inspired by the popular Mailbox App, implemented in Swift. Preview Exit Mode The .exit mode is the original behavi

Implementing and testing In-App Purchases with StoreKit2 in Xcode 13, Swift 5.5 and iOS 15.
Implementing and testing In-App Purchases with StoreKit2 in Xcode 13, Swift 5.5 and iOS 15.

StoreHelper Demo Implementing and testing In-App Purchases with StoreKit2 in Xcode 13, Swift 5.5, iOS 15. See also In-App Purchases with Xcode 12 and

An alternative SwiftUI NavigationView implementing classic stack-based navigation giving also some more control on animations and programmatic navigation.
An alternative SwiftUI NavigationView implementing classic stack-based navigation giving also some more control on animations and programmatic navigation.

swiftui-navigation-stack An alternative SwiftUI NavigationView implementing classic stack-based navigation giving also some more control on animations

FutureLib is a pure Swift 2 library implementing Futures & Promises inspired by Scala.

FutureLib FutureLib is a pure Swift 2 library implementing Futures & Promises inspired by Scala, Promises/A+ and a cancellation concept with Cancellat

ShogibanKit is a framework (not yet) for implementing complex Japanese Chess (Shogii) in Swift. No UI, nor AI.
ShogibanKit is a framework (not yet) for implementing complex Japanese Chess (Shogii) in Swift. No UI, nor AI.

ShogibanKit Framework Shogi, or Japanese Chess, is based on very complex rules, and it is hard to implement all basic rules. This ShogibanKit aims to

Demo implementing Modern MVVM with Combine and SwiftUI

ModernMVVM-Combine-SwiftUI Demo implementing Modern MVVM with Combine and SwiftUI Includes the following: Publishers feedback with needed extensions V

A Location Manager for easily implementing location services & geofencing in iOS. Ready for iOS 11.
A Location Manager for easily implementing location services & geofencing in iOS. Ready for iOS 11.

A Location Manager for easily implementing location services & geofencing in iOS, written in Objective-C. Ready for iOS 11. Features Get current/conti

Owner
null
Sign in with Apple, Sign up with Apple, or Continue with Apple

ContinueWithApple Sign in with Apple, Sign up with Apple, or Continue with Apple Utils 1. randomNonceString 로그인 요청마다 임의의 문자열인 'nonce'가 생성되며, 이 'nonce'

Hankyeol Park 0 Feb 26, 2022
A UIViewController subclass for Instagram authentication.

InstagramAuthViewController A ViewController for Instagram authentication. A UIViewController subclass that handles showing the Instagram login page,

Isuru Nanayakkara 38 Jun 29, 2021
FCLAuthSwift is a Swift library for the Flow Client Library (FCL) that enables Flow wallet authentication on iOS devices.

FCLAuthSwift is a Swift library for the Flow Client Library (FCL) that enables Flow wallet authentication on iOS devices. Demo The demo a

Zed 3 May 2, 2022
A simple project for Face ID Authentication for iOS device using LocalAuthentication Framework

BiometricAuthentication This respository is a simple project for Face ID Authentication for iOS device using LocalAuthentication Framework and infoPli

Lee McCormick 0 Oct 23, 2021
Example of simple OAuth2 authentication using Alamofire 5 and RxSwift library

REST Client based on Alamofire 5 and RxSwift library. Supports OAuth2 and Basic authentication interceptor.

Tomáš Smolík 3 Dec 8, 2022
A quick and simple way to authenticate an Instagram user in your iPhone or iPad app.

InstagramSimpleOAuth A quick and simple way to authenticate an Instagram user in your iPhone or iPad app. Adding InstagramSimpleOAuth to your project

Ryan Baumbach 90 Aug 20, 2022
A quick and simple way to authenticate a Dropbox user in your iPhone or iPad app.

DropboxSimpleOAuth A quick and simple way to authenticate a Dropbox user in your iPhone or iPad app. Adding DropboxSimpleOAuth to your project CocoaPo

Ryan Baumbach 42 Dec 29, 2021
A quick and simple way to authenticate a Box user in your iPhone or iPad app.

BoxSimpleOAuth A quick and simple way to authenticate a Box user in your iPhone or iPad app. Adding BoxSimpleOAuth to your project CocoaPods CocoaPods

Ryan Baumbach 15 Mar 10, 2021
Implementing User Authentication with Sign in with Apple

Implementing User Authentication with Sign in with Apple Provide a way for users of your app to set up an account and start using your services. Overv

Liselot 0 Dec 2, 2021
Sign in with Apple, Sign up with Apple, or Continue with Apple

ContinueWithApple Sign in with Apple, Sign up with Apple, or Continue with Apple Utils 1. randomNonceString 로그인 요청마다 임의의 문자열인 'nonce'가 생성되며, 이 'nonce'

Hankyeol Park 0 Feb 26, 2022