Native login with passkeys allows you to seamlessly integrate passkeys into your mobile applications. If you wanted to add passkeys before, you had to integrate a web redirect flow that uses Universal Login.
Today, we are announcing Limited Early Access to Native Login with passkeys for Android applications.
How Does It Work?
In order to use Native Login with passkeys in your Android application, there are a few requirements:
- Enable and configure your passkey policy: First of all, you need to enable passkeys for your tenant. Learn how to do it using our documentation.
- Configure a Custom Domain: you can learn how to configure a custom domain using our documentation.
- Enable Android App Links Support, which you can do following our docs.
Native login is available on the Android SDK from version 3.2.0 and Android API 28.
Sign Up
To sign up, you’ll need to use the "
signupWithPasskey
" method from the "AuthenticationAPIClient
". When successful, you can handle the passkey creation from your device using Android’s CredentialManager following Android’s official docs. Here’s an example implementation in Kotlin:val account = Auth0.getInstance("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}") val client = AuthenticationAPIClient(account) client.signupWithPasskey( UserData( email = "jndoe@email.com" ), "{realm}" ).start(object : Callback<PasskeyRegistrationChallenge, AuthenticationException> { override fun onSuccess(result: PasskeyRegistrationChallenge) { val passKeyRegistrationChallenge = result val request = CreatePublicKeyCredentialRequest( Gson().toJson( passKeyRegistrationChallenge.authParamsPublicKey ) ) var response: CreatePublicKeyCredentialResponse? // start credential creation on the device credentialManager.createCredentialAsync(requireContext(), request, CancellationSignal(), Executors.newSingleThreadExecutor(), object : CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException> { override fun onError(e: CreateCredentialException) { } override fun onResult(result: CreateCredentialResponse) { response = result as CreatePublicKeyCredentialResponse val authRequest = Gson().fromJson( response?.registrationResponseJson, PublicKeyCredentials::class.java ) // once the device created the key pair and signed the challenge you can sign in to Auth0 client.signinWithPasskey( passKeyRegistrationChallenge.authSession, authRequest, "{realm}" ) .validateClaims() .start(object : Callback<Credentials, AuthenticationException> { override fun onSuccess(result: Credentials) { credentialsManager.saveCredentials(result) Snackbar.make( requireView(), "Hello ${result.user.name}", Snackbar.LENGTH_LONG ).show() } override fun onFailure(error: AuthenticationException) { Snackbar.make( requireView(), error.getDescription(), Snackbar.LENGTH_LONG ).show() } }) } }) } override fun onFailure(error: AuthenticationException) { Snackbar.make( requireView(), error.getDescription(), Snackbar.LENGTH_LONG ).show() } })
The
signupWithPasskey
method starts the passkey creation ceremony. It generates the challenge for the authenticator to sign once it has created the public key credential pair. In your case, your Android device acts as the authenticator and you create the key pair and sign the challenge when you use the CreatePublicKeyCredentialRequest
method from Android’s Credential Manager. Then, you can use Android’s Credential Manager method
createCredential
or createCredentialAsync
to start the creation. Once successful, you can use the result from the creation to send that data to Auth0 and sign in using the signinWithPasskey
method, which is covered below.Login
To sign in, you’ll have to first initiate the passkey challenge by using the
passkeyChallenge
method from the AuthenticationAPIClient
. When the call is successful, you can initiate the credential retrieval using Android’s getCredential
method from the CredentialManager
.When your device retrieves the credential successfully, you can then initiate the sign-in process with Auth0. An example implementation could be:
val account = Auth0.getInstance("{YOUR_CLIENT_ID}", "{YOUR_DOMAIN}") val client = AuthenticationAPIClient(account) client.passkeyChallenge(realm) .start(object : Callback<PasskeyChallenge, AuthenticationException> { override fun onSuccess(result: PasskeyChallenge) { val passkeyChallengeResponse = result val request = GetPublicKeyCredentialOption(Gson().toJson(passkeyChallengeResponse.authParamsPublicKey)) val getCredRequest = GetCredentialRequest( listOf(request) ) credentialManager.getCredentialAsync(context, getCredRequest, CancellationSignal(), executor, object : CredentialManagerCallback<GetCredentialResponse, GetCredentialException> { override fun onError(e: GetCredentialException) { Log.w(TAG, "Error fetching public key credential") callback.onFailure(handleGetCredentialFailure(e)) } override fun onResult(result: GetCredentialResponse) { when (val credential = result.credential) { is PublicKeyCredential -> { val authRequest = Gson().fromJson( credential.authenticationResponseJson, PublicKeyCredentials::class.java ) // initiate signin process with Auth0 client.signinWithPasskey( passkeyChallengeResponse.authSession, authRequest, realm ) .validateClaims() .addParameters(parameters) .start(callback) } else -> { Log.w( TAG, "Received unrecognized credential type ${credential.type}." ) callback.onFailure(AuthenticationException("Received unrecognized credential type ${credential.type}")) } } } }) }
For more detailed examples, you can check out the Android SDK sample folder on Github.
If you need Java examples, you can check out this doc.
What Use Cases Are Supported?
The initial early access release provides support for the following use cases:
- Sign Up with a passkey: users can register a new passkey for Auth0/your app and store it in the device credential manager for future use.
- Login with a passkey: users can retrieve passkeys using the device’s credential manager and use them to log in.
How Can You Apply?
If you are interested in joining the early access program, please reach out to your account manager.
Any products, features, or functionality referenced in this material that are not currently generally available may not be delivered on time or at all. Product roadmaps do not represent a commitment, obligation, or promise to deliver any product, feature, or functionality, and you should not rely on them to make your purchase decisions.
About the author
Carla Urrea Stabile
Senior Developer Advocate
I've been working as a software engineer since 2014, particularly as a backend engineer and doing system design. I consider myself a language-agnostic developer but if I had to choose, I like to work with Ruby, Python, and Elixir.
After realizing how fun it was to create content and share experiences with the developer community I made the switch to Developer Advocacy. I like to learn and work with new technologies.
When I'm not coding or creating content you could probably find me going on a bike ride, hiking, or just hanging out with my dog, Dasha.