How do passkeys, Sign in with Apple and ASWebAuthenticationSession work in AuthenticationServices?

17.5.1 · L5 · Interview

Predict first

A registration request is built for a relying party. What does it carry?

import AuthenticationServices

let prov = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: "example.com")
let req = prov.createCredentialRegistrationRequest(challenge: Data([1, 2, 3]), name: "asha", userID: Data([9]))
print(req.relyingPartyIdentifier, req.name, req.challenge.count)
  • example.com asha 3
  • asha example.com 3
  • example.com asha 1

Mental model. A passkey is a lock that only opens for your face: the building (the site) keeps a copy of the lock, never your key, and the key only works at that building. A password is a spare key you hand out and hope no one copies.

AuthenticationServices is the framework for signing users in without the app handling raw credentials. Passkeys replace passwords with public-key credentials (WebAuthn/FIDO2): when a user registers, the device creates a key pair, keeps the private key in the (synced, end-to-end encrypted) iCloud Keychain, and gives the server the public key; to sign in, the server sends a random challenge, the device signs it after Face ID or Touch ID, and the server verifies the signature against the stored public key. There is no shared secret to phish or leak from a server breach, and a credential is bound to the relying party (your domain, example.com), so a look-alike site cannot use it. In code: build ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: "example.com"), call createCredentialRegistrationRequest(challenge:name:userID:) (the request carries the challenge, a user name and an opaque user id) or createCredentialAssertionRequest(challenge:), and run them with ASAuthorizationController, handling success and failure in its delegate. The domain must publish an apple-app-site-association file with a webcredentials entry and the app must have the Associated Domains capability (webcredentials:example.com), the same mechanism as universal links. Offer passkeys with AutoFill-assisted requests (the QuickType bar suggests them), keep a fallback for devices and users without them, and let users manage credentials.

Sign in with Apple (ASAuthorizationAppleIDProvider) returns a stable user identifier, an identity token (a JWT your server verifies) and an authorization code, and optionally the name and an email address (which may be Apple’s private relay address). The name and email arrive only on the first authorization, so store them immediately, and check credentialState(forUserID:) at launch because the user can revoke it in Settings. App Review requires it as an option if you offer other third-party social logins (with some exceptions). Password AutoFill (ASAuthorizationPasswordProvider and the textContentType fields) lets users sign in with saved passwords and ASCredentialProviderViewController lets your password manager provide credentials to the system. ASWebAuthenticationSession runs a web-based sign-in (OAuth, SAML, a company SSO) in a secure system browser sheet that shares cookies with Safari (so existing sessions give single sign-on) and returns the callback URL to the app, without the app being able to read the page or the credentials; use it, never an embedded WKWebView, for OAuth, with a universal-link or custom-scheme callback and prefersEphemeralWebBrowserSession for private sign-in. Combine these with PKCE for OAuth, store session tokens in the Keychain, and verify identity tokens and assertions server-side.

The request holds the relying party, the user name and the server’s challenge bytes.

Common traps

  • Using an embedded web view for OAuth. The app could read the credentials, and users cannot trust it; use ASWebAuthenticationSession.
  • Not saving the name and email on the first Sign in with Apple. They are only returned once; later authorizations omit them.

They might follow up with

  • What does a passkey server store? The public key and credential id; the private key never leaves the user’s devices.
  • Why is a passkey phishing-resistant? It is bound to the relying-party domain, so a look-alike site cannot use it.

Related questions

  • 17.5.2 How do Core Spotlight, NSUserActivity, Handoff and universal links make an app’s content discoverable and…
  • 17.7.1 How do you approach an unfamiliar Apple framework: what do you check before you write code, and how do you…
  • 6.7.3 What does the apple-app-site-association file contain, and how does the system verify a domain?

How do Core Spotlight, NSUserActivity, Handoff and universal links… →