Logo for tanaschita.com

Implementing Passkeys in iOS with AuthenticationServices

A practical introduction to passwordless authentication using passkeys on iOS.

02 Mar 2026 · 7 min read

Passkeys are credentials built to eliminate security problems like weak or reused passwords, credential leaks and phishing attacks.

In this article, we'll look at what passkeys are, how they work conceptually, and how to integrate them into an iOS app using Apple's AuthenticationServices framework.

Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE

What are passkeys?

Passkeys are a passwordless authentication method based on public-key cryptography. Instead of storing a password on a server, passkeys use:

  • A private key, securely stored on the user's device.
  • A public key, stored on the server.

When signing in, the server sends a cryptographic challenge. The device signs it using the private key, and the server verifies the signature using the public key.

The private key is securely retained on the device and synced with other devices, for example via iCloud Keychain.

Under the hood, passkeys are built on the WebAuthn and FIDO2 standards. As iOS developers, however, we do not need to implement those protocols manually, the system handles that for us.

How passkeys work in an iOS app

On iOS, passkeys are implemented using the AuthenticationServices framework.

There are two main flows:

  1. Registration - creating a new passkey.
  2. Authentication - signing in using an existing passkey.

In both cases, the backend plays a crucial role. It must:

  • Generate cryptographic challenges
  • Store public keys
  • Verify signed responses

The iOS app acts as a client in the WebAuthn flow.

Registering a passkey

A typical "sign up with passkey" flow looks like this:

  1. The user enters an identifier (for example an email) on the sign-up screen.
  2. The app asks the backend to start passkey registration.
  3. The backend returns a registration challenge and a stable user handle (a backend-generated user ID).
  4. iOS creates the passkey and returns attestation data.
  5. The app sends the attestation back to the backend, which verifies it and creates the account.

The same flow also works when a user is already signed in and wants to add a passkey as an additional login method.

After obtaining a challenge from the server, we can create an authentication request which presents a sheet to the user asking to create a new credential:

let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
relyingPartyIdentifier: "example.com")
let registrationRequest = provider.createCredentialRegistrationRequest(
challenge: challenge, displayName: email, userID: userID)
let authController = ASAuthorizationController([platformKeyRequest])
authController.delegate = self
authController.presentationContextProvider = self
authController.performRequests()

The relyingPartyIdentifier must match the associated domain configured via the Associated Domains capability.

When the user confirms with Face ID or Touch ID, the system creates a new key pair and returns a credential. In the delegate callback:

func authorizationController(
controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization
) {
if let credential = authorization.credential
as? ASAuthorizationPlatformPublicKeyCredentialRegistration {
let credentialID = credential.credentialID
let clientDataJSON = credential.rawClientDataJSON
let attestationObject = credential.rawAttestationObject
// Send these values to backend for verification
}
}

The backend then verifies the registration and stores the public key.

Authenticating with a passkey

The login flow is similar. The only difference is, that we now create an assertion request instead of a registration request:

let request = credetialProvider.createCredentialAssertionRequestWithChallenge(challenge)

When providing an assertion request to the controller and the user has one or more credentials on the device, the device displays a sheet with the list of credentials to choose from. If there aren't any credentials on the device, we get an error. In this case, we can ask the user to register.

Based on the credential that is passed into authorizationController(controller:didCompleteWithAuthorization:), we can determine the request type and take further steps.

func authorizationController(
controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization
) {
switch authorization.credential {
case let registration as ASAuthorizationPlatformPublicKeyCredentialRegistration:
// Send attestation data to backend (finish registration)
case let assertion as ASAuthorizationPlatformPublicKeyCredentialAssertion:
let signature = assertion.signature
let clientDataJSON = assertion.rawClientDataJSON
let authenticatorData = assertion.rawAuthenticatorData
let credentialID = assertion.credentialID
// Send signature and related data to backend (finish login)
default:
break
}
}

For authentication, the backend verifies the signature using the stored public key. If valid, the user is signed in.

Sponsorship logo
Preparing for a technical iOS job interview
Preparing for a technical iOS Job Interview with over 300 questions & answers. Covering Swift & Objective-C, SwiftUI & UIKit, Combine, HTTP Networking, iOS File System, Core Data, Concurrency with async/await, Security, Automated Testing, Dependency Management, AI & Machine Learning and more.
LEARN MORE
Sponsorship logo
Architecture & Design Patterns for iOS
This book is a practical guide to essential architectural principles and design patterns for iOS development. It covers strategies for building maintainable apps with Swift and SwiftUI, including dependency injection, navigation, common patterns, and modularization.
LEARN MORE
Sponsorship logo
Become a sponsor of tanaschita.com
By publishing an article on different iOS topics every week, tanaschita.com is constantly growing in the developer community and may provide a great audience for you as a sponsor.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

authentication

security

swift

swiftui

ios

Implementing Face ID authentication in SwiftUI

Learn how to add biometric authentication with passcode fallback to secure your app.

10 Feb 2025 · 5 min read

Latest articles and tips

© 2026 tanaschita.com

Privacy policy

Impressum