Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2025 Privacy & Security

WWDC25 · 22 min · Privacy & Security

What’s new in passkeys

Discover how iOS, iPadOS, macOS, and visionOS 26 enhance passkeys. We’ll explore key updates including: the new account creation API for streamlined sign-up, keeping passkeys up-to-date, new ways to drive passkey upgrades through automatic passkey upgrades and passkey management endpoints, and the secure import/export of passkeys. Learn how these improvements enhance user experience and security, and how to implement these updates in your apps to provide a smoother, more secure authentication experience. To get the most out of this video, first watch “Meet passkeys” from WWDC22.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

  • 0:00 — Introduction
  • 0:58 — The passkey journey
  • 3:30 — Account creation API
  • 10:48 — Keep passkeys up-to-date
  • 14:41 — Automatic passkey upgrades
  • 16:59 — Passkey management endpoints
  • 19:12 — Importing and exporting passkeys

Code shown on screen · 7 snippets

Account creation swift · at 6:33 ↗
// Account creation

@Environment(\.authorizationController) var authorizationController

func performPasskeySignUp() async throws {
    let provider = ASAuthorizationAccountCreationProvider()
    let request = provider.createPlatformPublicKeyCredentialRegistrationRequest(
        acceptedContactIdentifiers: [.email, .phoneNumber],
        shouldRequestName: true,
        relyingPartyIdentifier: "example.com",
        challenge: try await fetchChallenge(),
        userID: try await fetchUserID()
    )

    do {
        let result = try await authorizationController.performRequest(request)
        if case .passkeyAccountCreation(let account) = result {
            // Register new account on backend
        }
    } catch
        ASAuthorizationError
        .deviceNotConfiguredForPasskeyCreation {
        showPasswordSignUpForm = true
    } catch ASAuthorizationError.canceled {
        showPasswordSignUpForm = true
    } catch
        ASAuthorizationError.preferSignInWithApple {
        await performSignInWithApple()
    } catch { ... }
}
Changing the user name swift · at 12:30 ↗
// Changing the user name

try await ASCredentialUpdater()
    .reportPublicKeyCredentialUpdate(
        relyingPartyIdentifier: "example.com",
        userHandle: userHandle,
        newName: "[email protected]"
    )
Changing the user name javascript · at 12:58 ↗
// Changing the user name

await PublicKeyCredential.signalCurrentUserDetails({
    rpId: "example.com",
    userId: userHandle,
    name: "[email protected]",
    displayName: "[email protected]"
});
Revoking a passkey swift · at 13:07 ↗
// Revoking a passkey

try await ASCredentialUpdater()
    .reportAllAcceptedPublicKeyCredentials(
        relyingPartyIdentifier: "example.com",
        userHandle: userHandle,
        acceptedCredentialIDs: acceptedCredentialIDs
    )
Revoking a passkey javascript · at 13:46 ↗
// Revoking a passkey

await PublicKeyCredential.signalAllAcceptedCredentials({
    rpId: "example.com",
    userId: userHandle,
    allAcceptedCredentalIds: acceptedCredentialIds
});
Removing a password swift · at 14:04 ↗
// Removing a password

try await ASCredentialUpdater()
    .reportUnusedPasswordCredential(
        domain: "example.com",
        username: "[email protected]"
    )
Automatic passkey upgrade swift · at 15:36 ↗
// Automatic passkey upgrade

func signIn() async throws {
    let accountDetails = try await signInWithPassword()
    guard !accountDetails.hasPasskey else { return }

    let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
        relyingPartyIdentifier: "example.com")

    let request = provider.createCredentialRegistrationRequest(
        challenge: try await fetchChallenge(),
        name: accountDetails.userName,
        userID: accountDetails.userID,
        requestStyle: .conditional
    )

    do {
        let passkey = try await authorizationController.performRequest(request)
        // Save new passkey to the backend
    } catch { ... }
}

Resources