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

2022 Safari & WebSystem ServicesPrivacy & Security

WWDC22 · 33 min · Safari & Web / System Services / Privacy & Security

Meet passkeys

It’s time for a security upgrade: Learn how to add support for passkeys to create a quick and easy sign in experience for people, all while offering a radical increase to account security. Passkeys are simple and strong credentials built to eliminate phishing attacks. We’ll share how passkeys are designed with security in mind, show you how people will use them, go over how to integrate passkeys in your log in flow, and explore the platform and web APIs you need to adopt this feature.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 13 snippets

Associated Domains setup json · at 11:30 ↗
{
    "webcredentials": {
        "apps": [ "A1B2C3D4E5.com.example.Shiny" ]
    }
}
Annotating user name text field swift · at 11:47 ↗
override func viewDidLoad() {
    super.viewDidLoad()
    //Additional setup…

    userNameField.textContentType = .username
}
AutoFill-assisted passkey sign in swift · at 11:59 ↗
// AutoFill-assisted passkey request

func signIn() {
    let challenge: Data =  // Fetched from server
    let provider =
        ASAuthorizationPlatformPublicKeyCredentialProvider(
            relyingPartyIdentifier: "example.com")
    let request =
        provider.createCredentialAssertionRequest(
            challenge: challenge)

    let controller =
        ASAuthorizationController(
            authorizationRequests: [request])
    controller.delegate = self
    controller.presentationContextProvider = self

    // Start the request
    controller.performAutoFillAssistedRequests()
}
ASAuthorizationControllerDelegate callback swift · at 13:29 ↗
// Completing a passkey sign in

func authorizationController(controller: ASAuthorizationController,
     didCompleteWithAuthorization authorization: ASAuthorization) {
    
    guard let passkeyAssertion = authorization.credential as?
        ASAuthorizationPlatformPublicKeyCredentialAssertion
    else {  }

    let signature = passkeyAssertion.signature
    let clientDataJSON = passkeyAssertion.rawClientDataJSON

    // Pass these values to your server, and complete the sign in

}
Modal passkey sign in swift · at 16:05 ↗
// Modal passkey request

func signIn() {
    let challenge: Data =  // Fetched from server
    let provider =      
        ASAuthorizationPlatformPublicKeyCredentialProvider(
            relyingPartyIdentifier: "example.com")
    let request = 
        provider.createCredentialAssertionRequest(
            challenge: challenge)
    
    let controller = 
        ASAuthorizationController(
            authorizationRequests: [request])
    controller.delegate = self
    controller.presentationContextProvider = self

    // Start the request
    controller.performRequests()
}
HTML user name field annotation javascript · at 16:53 ↗
<input type="text" id="username-field" autocomplete="username webauthn" >
AutoFill-assisted passkey sign in on the web javascript · at 17:09 ↗
// AutoFill-assisted WebAuthn request (JavaScript)

function signIn() {
    if (!PublicKeyCredential.isConditionalMediationAvailable ||
        !PublicKeyCredential.isConditionalMediationAvailable()) {
        // Browser doesn't support AutoFill-assisted requests.
        return;
    }

    const options = {
        "publicKey": {
            challenge: … // Fetched from server
        },
        mediation: "conditional"
    };

    navigator.credentials.get(options)
        .then(assertion => { 
            // Pass the assertion to your server.
        });
}
Modal passkey sign in on the web javascript · at 18:14 ↗
// Modal WebAuthn request (JavaScript)

function signIn() {
    var options = {
        "publicKey": {
            challenge: … // Fetched from server
        }
    };

    navigator.credentials.get(options)
        .then(function (assertion) { 
            // Pass the assertion to your server.
    });
}
Modal passkey request with allow list swift · at 20:55 ↗
// Modal request with allow list

func signIn(userName: String) {
    let challenge: Data =  // Fetched from server
    let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
        relyingPartyIdentifier:"example.com")
    let request = provider.createCredentialAssertionRequest(
        challenge: challenge)

    let credentialIDs: [Data] =  // Fetched from server for provided userName
    request.allowedCredentials = credentialIDs.map(
        ASAuthorizationPlatformPublicKeyCredentialDescriptor.init(credentialID:))

    let controller = ASAuthorizationController(authorizationRequests: [request])
    controller.delegate = self
    controller.presentationContextProvider = self

    // Start the request
    controller.performRequests()
}
Modal passkey request with silent fallback swift · at 22:56 ↗
// Modal passkey request, silent fallback

func signIn() {
    let challenge: Data =  // Fetched from server
    let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(
        relyingPartyIdentifier:"example.com")
    let request = provider.createCredentialAssertionRequest(
        challenge: challenge)

    let controller = ASAuthorizationController(authorizationRequests: [request])
    controller.delegate = self
    controller.presentationContextProvider = self

    // Start the request
    controller.performRequests(options: .preferImmediatelyAvailableCredentials)
}
Silent fallback delegate callback swift · at 23:06 ↗
// Handling a silent fallback
    
func authorizationController(controller: ASAuthorizationController, 
    didCompleteWithError error: Error) {
    
    guard let error = error as? ASAuthorizationError else {  }

    if error.code == .canceled {
        // Either the user canceled the sheet, or there were no credentials available.
        showSignInForm()
    }
}
Combined credential request swift · at 24:40 ↗
// Combined credential modal request

func signIn() {
    let challenge: Data =  // Fetched from server
    let passkeyProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(
        relyingPartyIdentifier:"example.com")
    let passkeyRequest = passkeyProvider.createCredentialAssertionRequest(
        challenge: challenge)

    let passwordRequest = ASAuthorizationPasswordProvider().createRequest()
    let signInWithAppleRequest = ASAuthorizationAppleIDProvider().createRequest()

    let controller = ASAuthorizationController(
        authorizationRequests: [passkeyRequest, passwordRequest, signInWithAppleRequest])
    controller.delegate = self
    controller.presentationContextProvider = self

    // Start the request
    controller.performRequests()
}
Combined credential callback swift · at 25:02 ↗
// Completing a combined credential request

func authorizationController(controller: ASAuthorizationController, 
     didCompleteWithAuthorization authorization: ASAuthorization) {

    switch authorization.credential {
    case let passkeyAssertion as ASAuthorizationPlatformPublicKeyCredentialAssertion:
        finishSignIn(with: passkeyAssertion)

    case let signInWithAppleCredential as ASAuthorizationAppleIDCredential:
        finishSignIn(with: signInWithAppleCredential)

    case let passwordCredential as ASPasswordCredential:
        finishSignIn(with: passwordCredential)

    default:
        // Handle other credential types
        break
    }
}

Resources