Streaming is available in most browsers,
and in the Developer app.
-
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.
Resources
Related Videos
WWDC23
WWDC22
- Enhance your Sign in with Apple experience
- Support multiple users in tvOS apps
- What’s new in privacy
WWDC20
-
Download
♪ Mellow instrumental hip-hop music ♪ ♪ Hi, I'm Garrett, an engineer on the Authentication Experience team. And in this video, I'm excited to talk about passkeys, a next-generation authentication technology. But first, I need to talk about today's authentication technology: passwords. You're probably used to signing in to nearly every app and website with them. Passwords are really hard to use securely. All of us know we're supposed to create strong, unique passwords for every account, but not many people actually do. As you're designing your apps and websites, there's this constant tradeoff between keeping accounts secure and designing a good experience. And even if your apps and websites do everything right, issues like phishing and password reuse can still lead to account compromise. In macOS Monterey and iOS 15, we announced a developer preview of the solution -- passkeys -- and got so much great feedback. In macOS Ventura and iOS 16, we're excited to make passkeys available to everyone. Now is the time to adopt them. With passkeys, not only is the user experience better than a password, but also entire categories of security problems, like weak and reused credentials, credential leaks, and phishing, are just not possible anymore. And they're so easy to use. Let me show you. Let's start with our favorite demo app, Shiny. This app lets me see one cute picture a day and has a typical password-based sign-in flow. I can tap in the user name field and see an AutoFill suggestion for my account. I'll select that, sign in. Then, I can fill in my password.
Then, I wait around for a little bit until an SMS message comes in with my one-time code.
There it is. And eventually, I'm signed in. It took a few steps, but with the help of AutoFill and my password manager, I was able to get there.
Now that I'm signed in, I'll add a passkey to this account. Account Management, Add passkey. Here, I get the system sheet for creating a passkey. Continue. Done! In just a few taps, my device has generated a unique, cryptographically strong key pair for my account and stored it in my iCloud Keychain, so it will sync and work across all of my devices running macOS Ventura and iOS 16.
Now that I have a passkey, let me show you how easy it is to use. I'm going to sign out, and I'm back at the same sign-in form I used earlier. I'm going to focus the user name field like before. Now that I have a passkey saved for my account, it shows up in the QuickType bar. All I have to do is tap it and I'm signed in. One step. When saving the passkey, I didn't have to come up with a new password or try to satisfy any complexity requirements. Each passkey is generated by the system and guaranteed to be strong and only ever used for a single account. And when I'm signing in with it, it can be shown in the existing sign-in flows I'm used to, and it's a single tap to use. And the system will take care of only letting me use it in the correct app or website, with strong built-in phishing resistance. Of course, passkeys work on the web too. Here I am on Shiny's website in Safari. Just like on my phone, when I focus the user name field, my passkey is already there and ready to use, thanks to iCloud Keychain. All I have to do is Touch ID and I'm signed in. That's it. Apple's passkey implementation is built on open standards. We've been working with other platform vendors within the FIDO Alliance to make sure that passkey implementations are compatible cross-platform and can work on as many devices as possible. After upgrading my account to use a passkey, I'm still able to sign in to it on my friend's PC. Of course, my friend's PC doesn't have the passkey saved locally, but I can still type my user name here. When I press Sign In, I get a sheet that's offering to let me use my phone. Then I get a QR code. Let me scan that.
My phone recognizes that this QR code is for signing in with a passkey. When I select this option, my phone and the browser securely connect to each other. Now I can just Continue, and I'm signed in. This cross-platform sign-in experience is a first-class system feature that's part of the standards behind passkeys. On the surface, it appears incredibly simple, but this is not just a QR code. Behind the scenes, the devices are performing a local key agreement, proving proximity, establishing an end-to-end encrypted communication channel, all to let you sign in in a way that's easy but maintains the strong phishing resistance of passkeys. It works great for allowing me to sign in securely to my account on any device. Another important feature for a password replacement is the ability to share accounts between two or more people. To share a passkey with someone else, I can use AirDrop.
My partner and I also have an account for Shiny that we share, which I've already upgraded to use a passkey. With a passkey, the credential isn't something I could type, but I'm still able to share it with people I trust. On my phone, I'll open up the account details.
Here are all of my accounts, which use both passwords and passkeys. I can tap on our shared account to pull up more details. Here, I can get some information about my saved passkey or add a note to this account. I can also share my passkey. There's my partner's phone. I'll go ahead and select that.
Now my partner has the passkey too.
And that's how easy it is to use passkeys everywhere. I've just gone over the experience of using a passkey. Next, I'll talk about what a passkey is and some interface guidelines when using them. Then I'll show you how you can integrate passkeys into your existing sign-in flows in your apps and websites, by taking advantage of AutoFill, followed by some additional options that can further streamline your sign-in process. After that, I'll go into some more technical detail about how passkeys work and finally, discuss passkeys and multifactor authentication. First up, designing for passkeys. When it comes to talking about passkeys, first and foremost, passkeys are replacements for passwords. They're faster to sign in with, easier to use, and so much more secure. Here are some guidelines for how to refer to passkeys in your apps and websites. "Passkey" is a generic, user-visible term. This video focuses on Apple's implementation, but as I've just shown you, other major platforms have already started building their own support for passkeys. "Passkey" is also a common noun, like "password." In English, this means it's lowercase and gets pluralized like "password" would. I have a passkey for my account, and I can go to Settings to view all of my accounts with passkeys. On Apple platforms, you can also use the SF Symbol person.key.badge and the .fill variant to provide iconography consistent with the system. When it comes to offering passkeys in your apps and websites, you don't need to design entire new interfaces. The user name field is the center point for most app and website sign-in today. Pretty much everyone knows how to use it, and many apps and websites already take advantage of it to tailor the sign-in experience per account. Now the user name field has another big feature. While passkeys bring new paradigms for how signing in works, the transition away from passwords needs to be smooth and easy too. You can now present passkeys using AutoFill as a first-class feature, letting you drop them right in to your existing sign-in flows, in an interface that's familiar and people know how to use. Presenting passkeys with AutoFill is the primary way you should use them. For more advanced uses though, Apple platforms also have a wide range of additional UI options for signing in with passkeys. Here's how to get started using passkeys and presenting them with AutoFill. Passkeys are built on the WebAuthentication -- or WebAuthn standard -- and use public-key cryptography. Rather than having a typable word or string, unique cryptographic key pairs are generated for every account. You'll need to adopt WebAuthn on your server back end in order to perform passkey sign-in. Any standard WebAuthn server implementation should work with passkeys. In apps on Apple platforms, passkeys are part of the ASAuthorization API family in the AuthenticationServices framework. This is our API for working with all kinds of different credentials, including passwords, security keys, and Sign in with Apple. We've also added a few new methods you can use, like AutoFill support, to make this API even more flexible and let you fit it in seamlessly in your existing sign-in flows. To get started using passkeys in your apps, first, you'll need to set up associated domains, using the webcredentials service. You can find more details about that in the "Introducing Password AutoFill for Apps" and "What's new in Universal Links" videos. In your app's interface, make sure your user name field is using the user name textContentTtype. This lets the system know where to offer passkey suggestions. Once that's configured, here's the code needed to start an AutoFill-assisted passkey request. It's just a few simple steps when you break it down. As with any WebAuthn request, you'll first need to fetch a challenge from your server. Then create the provider and the request. ASAuthorizationPlatformPublicKey CredentialProvider is the ASAuthorizationProvider for working with passkey requests. In WebAuthn terms, assertions are used when signing in, so here, I'm creating an assertion request to sign in with an existing passkey. ASAuthorizationController is what actually handles the request. Create an instance with the passkey request and configure its delegate and presentationContextProvider. And finally, call performAutoFillAssistedRequests to start the request. While this request is running in your app, whenever a user name field is focused, the system will offer available passkeys in the QuickType bar. Make sure to start this request early in your view lifetime before a user name field gets focused, so passkeys are ready when the keyboard appears. When an item from the QuickType bar is selected, Face ID gets invoked, then you'll receive an ASAuthorizationController Delegate callback to complete the sign-in. Nothing actually gets filled in your text field. When an authorization succeeds for any credential type, you'll get the didCompleteWithAuthorization callback. The first thing you should do is check the type of the credential that you got. In the case of passkey sign-in, it will be an ASAuthorizationPlatformPublicKey CredentialAssertion. The assertion object will contain the fields needed to verify the sign-in on your back end. You should read the values, verify them with your server, and complete the sign-in. AutoFill-assisted passkey requests are powerful. With that small code change, your app's sign-in flow now offers a lot of flexibility. The primary case, of course, is to select the passkey suggestion from the QuickType bar to sign in quickly with that passkey. This is what you should expect to happen most often. There are other options though. The code I just showed you also allows passkey sign-in from nearby devices with no additional changes. You can tap the key icon to bring up a view that lists all available passkeys and passwords and get to the option to sign in with a nearby device. Then you can perform a cross-device passkey sign-in. In both cases, if a passkey is used, you'll receive the same ASAuthorizationController Delegate callback. There's nothing special you need to do to support this. If a user doesn't have any passkeys yet, they can just use your login form like they're used to. They'll get password suggestions in the QuickType bar, or they can just type in the fields. If a password item is selected, the credential will still be filled in to your text fields, and you can cancel the running request. We designed this API to let you drop it right in to your existing sign-in flows and make it super easy for your users. If someone that has already upgraded to using a passkey decides to enter their user name anyway instead of using the AutoFill suggestion, you should cancel the AutoFill request and use ASAuthorizationController to present a modal passkey sign-in sheet. From here, it's still a single tap, and you'll receive the same ASAuthorizationController Delegate callback. Here's the code from before. To switch this from an AutoFill request to a modal request, just swap this performAutoFillAssistedRequests method call with a performRequests() call. This will present a modal sheet with all available passkeys as well as the option to use a passkey from a nearby device. Those are the only code changes you need in your app to support passkeys. The web platform also supports both AutoFill-assisted and modal passkey requests. On the web, passkeys are used via standard WebAuthn API, which is also used for security keys. Just like in apps, adopting AutoFill-assisted requests allows signing in quickly with just a Touch ID, getting to all of your available passkeys and passwords or using a passkey from a nearby device, all with very little code. First off, make sure to annotate your user name field on your webpage with both the username and webauthn autocomplete detail tokens, so that both password and passkey suggestions are shown in the right place. Once that's done, here's a typical WebAuthn sign-in, in JavaScript. In WebAuthn, AutoFill-style requests are invoked using conditional mediation. You should start by using standard JavaScript feature detection to check if it is available. If it is, you can proceed making your request. Just like with a native API, you'll start by making a request using a challenge fetched from your server. To make it an AutoFill-assisted request, add the mediation: "conditional" parameter to your options. Then, use navigator.credentials .get to start the request. The .get call returns a promise. If it resolves, you'll receive an assertion object, which you can send back to your server to verify, then complete the sign-in. Like in apps, if someone manually enters a user name for an account with a passkey, you should use the API to present a modal sign-in sheet. To switch to a modal request, all you need to do is remove the mediation: "conditional" parameter. One thing to note when using WebAuthn is how Apple platforms handle user verification -- or UV. UV is a Boolean field in a WebAuthn response that indicates whether the authenticator attempted to verify that the current user is the owner of the device. On Apple devices, a value of one indicates that biometrics, or a password or passcode were used. Apple platforms will always require UV for passkeys when biometrics are available, so you don't have to worry about that. When making WebAuthn requests, there's an option to specify a user-verification requirement. The default value is userVerification: "preferred". Always use the default value to avoid creating a bad experience on devices without biometrics. Here are some additional notes for using passkeys on the web. When you make AutoFill-assisted requests, you should make them early in the page lifetime, just like in apps. For modal WebAuthn requests, you should trigger them from a user gesture event, such as a button click. A modal request can be triggered once per page load outside of a user gesture event, but WebKit may limit subsequent calls on that page if you do so. AutoFill requests are not modal, so they don't require a user gesture and have a much longer timeout. Finally, passkeys are replacing Safari's legacy platform authenticator. Existing credentials will still work and still be bound to the device they were created on, but new platform credentials will be created as passkeys. They can be differentiated from legacy credentials during registration, as passkeys will not provide an attestation statement. That's passkeys and AutoFill. Next up, I'll go over some additional platform features that can further streamline your sign-in experience. In addition to the AutoFill-assisted sign-in, the ASAuthorization API provides many more useful features. I'm going to cover three additional features of the API and when you might want to use them. Starting with passkey allow lists. When presenting a modal passkey sheet after a user name is entered, it's possible that there are passkeys for multiple accounts saved on the device. All available passkeys will be shown in the sheet by default. You can use a passkey allow list to restrict which passkeys are shown in the sheet, so that only the matching account is offered. To add an allow list to a modal request, you'll first need the user name. You can use that user name to fetch a list of matching credential IDs and turn it into an allow list. A credential ID is a unique identifier for a passkey. A Webauthn server should have a way to look up credential IDs for a given user name. From here, just proceed with your request like before. Now, on my device which has three Shiny accounts using passkeys, the sheet only offers the single account I'm trying to use. When making modal requests, you should use an allow list when you have additional context about which account the user is trying to sign in with, such as if they've already typed in their user name. Next up, I'll cover what happens you make a modal passkey request if there are no passkeys saved on the current device. This also applies if you use an allow list and none of the saved passkeys match that list. By default, when you make a modal passkey request, if there are no matching passkeys available, the modal sheet will be displayed and will immediately show the QR code for signing in with a passkey from a nearby device. This provides most flexibility when signing in and is the best option when you know a passkey is being used. But there's a new option in the API to prefer credentials that are immediately available and fall back silently with a delegate callback if there aren't any. This can be used to quickly offer up existing credentials when possible, before even showing a traditional sign-in form. This modal request using the default options will fall back to showing a QR code if there are no matching passkeys on the current device. If you use the preferImmediately AvailableCredentials option, instead of getting a QR code, you'll receive a delegate callback with an error. If you receive an ASAuthorizationError with a code of canceled, that means either the user saw the sheet and manually dismissed it, or you passed preferImmediately AvailableCredentials and no credentials were immediately available. What you do from here depends on the context where you were calling this from. For example, if you were using this option as a way to test for local credentials before showing your normal sign-in form, this is where would trigger showing your form. If there's at least one matching credential on the device, the full modal sheet will be displayed regardless of the options used. Make sure you're also using either AutoFill-assisted requests or modal requests with the default fallback somewhere in your app, so that the option to sign in with a nearby device is still reachable if there are no passkeys on the current device. The last feature of the ASAuthorization API that I'll cover is making combined credential requests. In this example, the app made a request for passkeys, passwords, and Sign in with Apple. My device happens to have three different credentials for three different accounts saved, so they're all presented here. But a more likely scenario is that someone would only have a single account. In that case, this same combined credential request will only offer one account in the sheet. Adding additional credential types to an existing ASAuthorization request is really easy. You just need to create providers and requests for the additional request types, then pass those new requests to your controller. Now, the modal sheet will offer whatever credentials are available from any of these credential types. You'll get the same delegate callback regardless of which credential type is used. You should check the type of the credential you received and finish the sign-in as appropriate for that credential type. So that covers a few of the more advanced features of the ASAuthorization API family. Now, I'm going to dig in to some more technical details about how passkeys actually work and what makes them so secure. When you sign in with a password today, generally what's actually happening is after you enter that password, it gets hashed and salted, and the resulting obfuscated value is sent to the server, which stores it. Later, if you can produce the same hashed salted value, you're allowed into the account. This means the server is responsible for storing this derivation of your password, which is highly valuable to attackers. If they can get it, it's possible to figure out what your password is and gain access to your account. Passkeys, however, work very differently. Rather than having a single, typeable string, a passkey is actually a pair of related keys. These keys are generated by your devices, securely and uniquely, for every account. One is public and is stored on the server. The other is private and stays on your devices even when signing in. The public key is not a secret. It's just as public as your user name. The private key is what is needed to actually sign in. The server never learns what your private key is, and your devices keep it safe. When you go to sign in, the server sends your device a single-use challenge. WebAuthn allows many different challenge-response algorithms, but passkeys on Apple platforms use standard ES256. Only your private key is capable of producing a valid solution to the challenge for your account. Your device produces this solution -- called a signature -- locally, and only sends the solution back to the server. Your private key stays secret and only on your devices. The server then validates the solution using your public key. If the solution your device provided is valid, you're signed in! A public key can be used to check if a solution is valid but is not able to produce a solution itself. This means the server can be sure that you have the right private key, without knowing what the private key actually is. And since the server doesn't know any private keys, it's a less valuable target for attackers, because there are no user credentials to leak. All of this cryptography and key protection is totally transparent and performed by the devices. Your customers never have to know or think about it. From their perspective, passkeys are super simple and just work, everywhere. Passkeys can also be used to sign in across devices in a secure, phishing-resistant manner. Here's how that works. There are two devices here. The client, which is the device or web browser where I'm signing in, and the authenticator, which is the device which has my passkey. First, the client shows a QR code, which the authenticator scans. This QR code contains a URL that encodes a pair of single-use encryption keys. Then, the authenticator produces a Bluetooth advertisement containing routing information for a network relay server. This local exchange allows selecting a server and sharing routing information, but also serves two additional functions. It performs an out-of-band key agreement that the server can't see, so everything going over the network is end-to-end encrypted and the server can't read anything. It also provides a strong claim that these two devices are in physical proximity. That means a QR code sent in an email or generated on a fake website won't work, because a remote attacker won't be able receive the Bluetooth advertisement and complete the local exchange. So that's the local part. Once the local exchange and key agreement have happened, the two devices connect to a relay server picked by the phone. From there, they perform a standard FIDO CTAP operation, which is encrypted using the keys from earlier, so the relay server can't see anything that's going on.
This whole process is performed by the device and the web browser. The website is not involved at any point in the cross-device communication. Cross-device cross-platform sign-in is a system feature that just works anywhere passkeys can be used. So that's a more technical look into how passkeys work and how they can make such strong security guarantees, even across devices. Next up, multifactor authentication. A common way to think about authentication today is in terms of factors. Different factors are strong or weak against different kinds of attacks, and combining factors can provide better collective coverage. But with passkeys, you don't need to think like that anymore. Here are some of the most common methods used to sign in today. Passwords in your head are vulnerable to pretty much everything. Password managers are good at generating unique, high-entropy strings, may have local protections against device theft, and offer some hints about phishing. Adding an SMS or time-based code can help with theft or phishing in some circumstances but doesn't really solve either. With passkeys though, every passkey is a unique, device-generated key pair. On Apple devices, they're built on a strong foundation of local device protections. Passkeys also completely eliminate the human factor from phishing. And they can't be leaked by an app or website server, because the servers don't have the private keys. Adding factors to a password-based sign-in flow makes sense, as together they can protect against more types of attacks than passwords alone. But a passkey alone protects against so much more that it doesn't need additional factors. I'm looking forward to a future without passwords. Here's how you can get started making that happen. First off, you'll need to adopt WebAuthn on your server, if you haven't already done so. Passkeys should work with any standard WebAuthn server implementation. Once your server is ready to go, adopt our new API in your apps and websites. AutoFill-assisted passkey requests can be dropped right in to your existing sign-in flows, plus we have a range of more advanced UI options as well, if you need them. And finally, transition your users away from passwords. Passkeys are an industry-standard solution to the convenience and security problem of securely signing in to apps and websites. By guiding your customers to passkeys and away from passwords, you can give them an incredibly quick and convenient sign-in experience while raising the security bar for everyone. Thank you. ♪
-
-
11:30 - Associated Domains setup
{ "webcredentials": { "apps": [ "A1B2C3D4E5.com.example.Shiny" ] } }
-
11:47 - Annotating user name text field
override func viewDidLoad() { super.viewDidLoad() //Additional setup… userNameField.textContentType = .username }
-
11:59 - 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() }
-
13:29 - 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 … }
-
16:05 - 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() }
-
16:53 - HTML user name field annotation
<input type="text" id="username-field" autocomplete="username webauthn" >
-
17:09 - 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. }); }
-
18:14 - 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. }); }
-
20:55 - 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() }
-
22:56 - 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) }
-
23:06 - 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() } }
-
24:40 - 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() }
-
25:02 - 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 } }
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.