Native Passkeys for Mobile Applications

Passkeys are a phishing-resistant alternative to traditional forms of authentication (such as username and password) that offer an easier and more secure user experience. They are modeled from FIDO® W3C Web Authentication (WebAuthn) and Client to Authenticator Protocol (CTAP) specifications.

Auth0 currently supports passkeys as an authentication method for database connections and offers two methods of implementation:

To learn more about implementing passkeys for mobile applications, review the information below.

How it works

Native passkeys use a combination of the Auth0 Authentication API and native iOS or Android APIs to embed challenge flows directly into your mobile application. This allows you to create an integrated signup and login experience for your application that does not rely on redirecting users through their browsers to complete authentication.

The following example demonstrates what a new user may experience during the passkey signup flow:

  1. A new user launches your mobile application and accesses the login screen. Since they are a new user, they select the Sign Up button.

  2. On the next screen, the user enters their email address and selects Create Account.

  3. Next, the user is asked if they want to create a passkey for your application. To proceed, the user selects Continue.

  4. To generate a passkey, the user must locally authenticate on their device using biometrics or another authentication method, such as entering a PIN. 

  5. After local authentication is complete, a new passkey is saved to the user’s device and synced with their passkey provider, such as iCloud or Google. 

  6. After the passkey is saved, the user continues your new user registration process to finalize their account. 

Once this process is complete, the user can authenticate with their saved passkey the next time they log in to your application.

Before you begin

Configure a custom domain

Native passkeys require the use of a custom domain. Before proceeding, ensure you have configured a custom domain for your tenant. To learn more, review Custom Domains.

Configure your passkey policy

Before you can implement native passkeys for Android or iOS applications, you must configure a passkey policy in your Auth0 tenant. To prepare your tenant, follow the steps in Configure Passkey Policy.

Prepare your application

To prepare your application for native passkeys, you must configure your Device Settings and add the Passkey grant. You can complete these configurations through your Auth0 Dashboard or the Management API.

Auth0 Dashboard

  1. Navigate to Applications > Applications and select the application you wish to update.

  2. At the bottom of the Settings tab, select Advanced Settings. Then, choose the Device Settings tab.

  3. Complete the iOS and Android sections as needed for your application. Then, click Save Changes.

  4. In the Advanced Settings section, select the Grant Types tab.

  5. Enable the Passkey grant, then select Save Changes.

Management API

Call the Update a Client endpoint and:

  • Update grant_types to include urn:okta:params:oauth:grant-type:webauthn.

  • Use the mobile object to specify iOS and Android device settings as needed.

Implement passkey flows

You can define the following passkey flows for your application:

  • Signup flow: Allows new users to generate and save a passkey during the user registration process.

  • Login flow: Allows an existing user who has already enrolled in passkeys to authenticate with their saved passkey during the login process.

Signup flow

A user initiates the passkey signup flow when they first attempt to log in to your application.

If the user provides an identifier that already exists, it’s recommended that you prompt the user to complete the login flow instead. Otherwise, the action will fail. 

Flow steps

  1. A user visits your application and chooses to register a new account. The user provides an identifier requested by your application, such as their email address. 

  2. Your application then initiates the signup challenge by calling the Request Signup Challenge endpoint of the Auth0 Authentication API:

    POST /passkey/register
    Content-Type: application/json
    
    {
      "client_id": "<CLIENT_ID>",
      "realm": "<OPTIONAL_CONNECTION>",
      "user_identifier": {
    	  "email": "<VALID_EMAIL_ADDRESS>",
    	  "name": "<OPTIONAL_USER_DISPLAY_NAME>,
      }
    }

    Was this helpful?

    /

  3. In response, Auth0 returns PublicKeyCredentialCreationOptions along with an auth_session ID:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "authn_params_public_key": {
        "challenge": "<GENERATED_CHALLENGE_FOR_THIS_SESSION>",
        "timeout": <MILLISECONDS>,
        "rp": {
          "id": "<THE_CUSTOM_DOMAIN>",
          "name": "<APPLICATION_NAME>"
        },
        "pubKeyCredParams": [
          { type: 'public-key', alg: -8 },
          { type: 'public-key', alg: -7 },
          { type: 'public-key', alg: -257 }
        ],
        "authenticatorSelection": {
          "residentKey": "required",
          "userVerification": "preferred"
        },
        "user": {
          "id": "<GENERATED_ID>",
          "name": "<USER-ENTERED_IDENTIFIER>",
          "displayName": "<USER-ENTERED_DISPLAY_NAME_OR_IDENTIFIER_IF_MISSING"
        }
      },
      "auth_session": "<SESSION_ID>"
    }

    Was this helpful?

    /

  4. Your application then completes the user registration process using the appropriate native APIs:

  5. Your application then uses the credential information obtained through the registration process, including authn_response details, to call the Token endpoint:

    POST /oauth/token
    Content-Type: application/json
    
    {
      "grant_type": "urn:okta:params:oauth:grant-type:webauthn",
      "scope": "<OPTIONAL_REQUESTED_SCOPE>",
      "audience": "<OPTIONAL_REQUESTED_AUDIENCE>"
      "auth_session": "<SESSION_ID_FROM_THE_FIRST_REQUEST>",
      "authn_response": {
        "id": "<BASE64URL_ID>",
        "rawId": "<BASE64URL_RAWID>",
        "type": "public-key",
        "authenticatorAttachment": "platform|cross-platform",
        "response": {
          "clientDataJSON": "<BASE64URL_CLIENT_DATA_JSON>",
          "attestationObject": "<BASE64URL_ATTESTATION_OBJECT>",
          <OTHER_PROPERTIES>
        }  
    }

    Was this helpful?

    /

  6. Auth0 creates a new user account and returns the requested tokens to complete the flow:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "access_token": "<BASE64_TOKEN>",
      "refresh_token": "<BASE64_TOKEN>",
      "id_token": "<BASE64_TOKEN>",
      "token_type": "Bearer",
      "expires_in": <SECONDS>
    }

    Was this helpful?

    /

Login flow

An existing user initiates the passkey login flow when they attempt to log in to your application. This flow only applies to existing users who have saved passkeys to their accounts during initial signup.

Flow Steps

  1. A user launches your application and begins the login process. Your application then initiates the login challenge by calling the Request Login Challenge endpoint of the Authentication API:

    POST /passkey/challenge
    Content-Type: application/json
    
    {
      "client_id": "<CLIENT_ID>",
      "realm": "<OPTIONAL_CONNECTION>"
    }

    Was this helpful?

    /

  2. In response, Auth0 returns PublicKeyCredentialRequestOptions along with an auth_session to continue the flow in your application:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "authn_params_public_key": {
        "challenge": "<GENERATED_CHALLENGE_FOR_THIS_SESSION>",
        "timeout": <AUTH_TIMEOUT_IN_MILLISECONDS>,
        "rpId": "<CUSTOM_DOMAIN>",
        "userVerification": "preferred"
      },
      "auth_session": "<SESSION_ID>"
    }

    Was this helpful?

    /

  3. Your application then completes the login process using the appropriate native APIs:

  4. Your application then uses the credential information obtained through the login process, including authn_response details, to call the Token endpoint:

    POST /oauth/token
    Content-Type: application/json
    
    {
      "grant_type": "urn:okta:params:oauth:grant-type:webauthn",
      "scope": "<OPTIONAL_REQUESTED_SCOPE>",
      "audience": "<OPTIONAL_REQUESTED_AUDIENCE>"
      "auth_session": "<SESSION_ID_FROM_THE_FIRST_REQUEST>",
      "authn_response": {
        "id": "<BASE64URL_ID>",
        "rawId": "<BASE64URL_RAWID>",
        "type": "public-key",
        "authenticatorAttachment": "platform|cross-platform",
        "response": {
          "authenticatorData": "<BASE64URL_AUTHENTICATORDATA>",
          "clientDataJSON": "<BASE64URL_CLIENTDATAJSON>",
          "signature": "<BASE64URL_SIGNATURE>",
          "userHandle": "<BASE64URL_USERHANDLE>"
        },
        "clientExtensionResults": <OPTIONAL_OBJECT>
    }

    Was this helpful?

    /

  5. Auth0 authenticates the credentials and returns the requested tokens to complete the flow:

    HTTP/1.1 200 OK
    Content-Type: application/json
    
    {
      "access_token": "<BASE64_TOKEN>",
      "refresh_token": "<BASE64_TOKEN>",
      "id_token": "<BASE64_TOKEN>",
      "token_type": "Bearer",
      "expires_in": <SECONDS>
    }

    Was this helpful?

    /

References

The following resources can be referenced when implementing native passkeys for your mobile application: