DEV Community

Wesley de Groot
Wesley de Groot

Posted on • Originally published at wesleydegroot.nl on

Implementing Sign in with Apple

DEV.to readers, this article may be updated, the latest version is available here: https://wesleydegroot.nl/blog/Implementing-Sign-in-with-Apple

Sign in with Apple is a user-friendly authentication method that allows users to sign in to apps and websites using their Apple ID.

In this blog post, we'll explore how to integrate Sign in with Apple into your Swift-based iOS app for UIKit and SwiftUI based apps.

Overview

Sign in with Apple is a powerful authentication solution that simplifies user access to apps and websites.

Here's what you need to know:

  1. Easy Sign-In : Instead of cumbersome forms and password management, users can sign in using their Apple ID. No more remembering passwords or verifying email addresses!

  2. Privacy First : Apple prioritizes user privacy. Data collection is limited to the user's name and email address. Plus, Apple's private email relay ensures that users receive emails while keeping their address confidential.

  3. Two-Factor Authentication : Every account using Sign in with Apple is automatically protected with two-factor authentication. Users on Apple devices can reauthenticate anytime with Face ID or Touch ID.

  4. Cross-Platform Compatibility : Sign in with Apple works seamlessly across iOS, iPadOS, macOS, tvOS, and watchOS. It's also compatible with any browser, making it suitable for web and app development.

  5. Antifraud Measures : Detect fake accounts with Apple's on-device machine learning. Get a privacy-friendly signal to identify genuine users.

Prerequisites

Before diving into implementation, ensure you have the following:

  1. Apple Developer Account : You'll need an active Apple Developer account to configure Sign in with Apple.

  2. Xcode : Make sure you have Xcode installed on your development machine.

Step-by-Step Implementation

1. Configure Your Project

  1. Open your project in Xcode.
  2. Navigate to the Signing & Capabilities pane.
  3. Set a unique bundle identifier for your app.
  4. Add your Apple ID account and assign the target to a team (enabling Sign in with Apple capability).

2. Add the Sign in with Apple Button

In your view controller or SwiftUI view, add the Sign in with Apple button. Here's how:

UIKit (View Controller)

import AuthenticationServices

class LoginViewController: UIViewController {
    func setupProviderLoginView() {
        let authorizationButton = ASAuthorizationAppleIDButton(
            type: .signIn,
            style: .whiteOutline
        )

        authorizationButton.addTarget(
            self,
            action: #selector(handleAuthorizationAppleIDButtonPress),
            for: .touchUpInside
        )

        self.addSubview(authorizationButton)
    }

    @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()
    }
}

// MARK: - Sign in with Apple
extension LoginViewController: ASAuthorizationControllerDelegate,
                               ASAuthorizationControllerPresentationContextProviding {
    func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        return self.view.window!
    }

    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
            let JWTToken = appleIDCredential.identityToken
            let authCode = appleIDCredential.authorizationCode

            dump(appleIDCredential)
            // Close login window.

        case let passwordCredential as ASPasswordCredential:
            // Sign in using an existing iCloud Keychain credential.
            let username = passwordCredential.user
            let password = passwordCredential.password

            print(passwordCredential)
            // Close login window

        default:
            break
        }
    }

    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // Handle error.
        print("Something went wrong", error)
    }

    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()
    }
}
Enter fullscreen mode Exit fullscreen mode

SwiftUI

import SwiftUI
import AuthenticationServices

struct ContentView: View {
    var body: some View {
        SignInWithAppleButton(.signIn) { request in
            request.requestedScopes = [.fullName, .email]
        } onCompletion: { result in
            switch result {
            case .success(let authorization):
                if let userCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
                    dump(userCredential)
                }

            case .failure(let error):
                print("Could not authenticate: \(error.localizedDescription)")
            }
        }
        .signInWithAppleButtonStyle(.whiteOutline)
        .frame(width: 280, height: 45)
    }
}
Enter fullscreen mode Exit fullscreen mode

Download SwiftUI Playground

SignInWithAppleButton(.label)

.continue: Continue label

signIn: Sign in with Apple label on the button.

signUp: Sign up with Apple label on the button.

.signInWithAppleButtonStyle(.style)

black: black button.

white: white button.

whiteOutline: white-outlined button.

Error codes

ASAuthorizationError.unknown: Unknown error.

ASAuthorizationError.canceled: User canceled the request.

ASAuthorizationError.failed: Authorization failed.

ASAuthorizationError.invalidResponse: Invalid response.

ASAuthorizationError.notHandled: Request not handled.

ASAuthorizationError.unknown: Unknown error.

3. User is signed in

Cache the name and email address of the user, this will be given once to the application.

Caveats

The user's name and email are only given once, this is expected behaviour.

It is recommened that you securely cache the initial ASAuthorizationAppleIDCredential containing the user info until you can validate that an account has succesfully been created on your server.

Source: https://forums.developer.apple.com/thread/121496#379297

Server-side validation may be needed, depending on your needs.

Conclusion

Sign in with Apple provides a seamless and secure authentication experience for your users.

It's easy to implement for usage in your app.

Resources

https://developer.apple.com/documentation/authenticationservices/implementing_user_authentication_with_sign_in_with_apple

Top comments (0)