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 ↗Code shown on screen · 13 snippets
Associated Domains setup
{
"webcredentials": {
"apps": [ "A1B2C3D4E5.com.example.Shiny" ]
}
} Annotating user name text field
override func viewDidLoad() {
super.viewDidLoad()
//Additional setup…
userNameField.textContentType = .username
} AutoFill-assisted passkey sign in
// 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
// 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
// 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
<input type="text" id="username-field" autocomplete="username webauthn" > AutoFill-assisted passkey sign in on the web
// 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
// 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
// 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
// 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
// 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
// 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
// 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
Related sessions
-
16 min -
16 min -
20 min -
23 min -
15 min -
23 min