Passage Passkey Flex docs are in beta. Passkey Complete docs can be found at docs.passage.id.

Authenticate

Confirm a user's identity for login or other secure actions.

Get started by choosing your client and backend for personalized docs.
Select client
Select backend

Prerequisites

Complete the steps to create a Passage app and install the necessary SDKs.

Ways to authenticate

Confirm a user's identity for login or other secure actions. There are three ways to authenticate users:

Authenticate with an external identifier

Users input an external identifier such as an email address, username, or phone number. Passage then authenticates them with the passkey associated with their external identifier.

Get transaction ID

Get a transaction ID from the Passage Backend for each user. Learn more about transactions.

Retrieve the user in your database, then call Passage with the user's external identifier.

If the user doesn't exist, you'll need to register them first.

Backend
import { PassageFlex } from '@passageidentity/passage-flex-node';
 
const passage = new PassageFlex({
    appId: process.env.PASSAGE_APP_ID,
    apiKey: process.env.PASSAGE_API_KEY,
});
 
app.post('/user/authenticate-with-passkey', async (req: Request, res: Response) => {
 
    // Using the identifier the user inputs, find the user in your database.
    const user = User.find({ email: req.body.email });
 
    // Use the user's identifier to retrieve a transaction ID.
    // Can be any external identifier.
    const transactionID = await passage.createAuthenticateTransaction({
        externalId: "UUID-string"
    });
 
    return transactionID;
});

Learn more about the Node SDK

Authenticate user

The WebAuthn (opens in a new tab) flow needs to be triggered from the client to authenticate the passkey on the user's device.

Initialize a Passage instance using your app ID found in Passage Console (opens in a new tab). Authenticate the user using the transaction ID you retrieved in step 2.

Client
import { PassageFlex } from 'passage-flex-js';
 
const passage = new PassageFlex(appID);
 
async function onLoginClick() {
    const transactionId = // Result of request to example '/user/authenticate-with-passkey' endpoint with `identifier`
    const nonce = await passage.passkey.authenticate(transactionID);
 
    const authResult = // Result of request to example '/user/verify` endpoint with `nonce`
}

Learn more about the JavaScript SDK

Verify nonce & return auth identifier

From your server, verify the nonce with the Passkey Flex backend SDK.

Backend
app.post('/user/verify', async (req: Request, res: Response) => {
    const { nonce } = req.body;
    try {
        const externalId = await passage.verifyNonce(nonce);
 
        res.json({
            auth_token: 'auth_token_or_other_auth_solution',
        });
    } catch (err) {
        res.status(response.status).json({ error: 'Error' });
    }
});

Learn more about the Node SDK

Authenticate without an external identifier

Users do not provide an external identifier. All passkeys associated with that app on the user's device are provided for authentication.

Authenticate user

Initialize a Passkey Flex instance using your app ID found in Passage Console (opens in a new tab).

Passkey Flex triggers the WebAuthn (opens in a new tab) flow. Users are shown all app passkeys registered to the device on their screen.

Client
import { PassageFlex } from 'passage-flex-js';
 
const passage = new PassageFlex(appID);
 
async function onLoginClick() {
    const nonce = await passage.passkey.authenticate();
    const authResult = // Result of request to example '/user/verify` endpoint with `nonce`
}

Learn more about the JavaScript SDK

Verify nonce & return auth identifier

From your server, verify the nonce with the Passkey Flex backend SDK.

Backend
app.post('/user/verify', async (req: Request, res: Response) => {
    const { nonce } = req.body;
 
    try {
        const externalId = await passage.verifyNonce(nonce);
 
        res.json({
            auth_token: 'auth_token_or_other_auth_solution',
        });
    } catch (err) {
        res.status(response.status).json({ error: 'Error' });
    }
});

Learn more about the Node SDK

Authenticate with passkey autofill (web only)

Also known as conditional mediation. This requires users to have a discoverable credential and a web browser that supports passkey autofill. Users select an identifier input field and the browser displays available passkeys in an autofill dropdown. The order of the tokens in the autofill HTML attribute must be username followed by webauthn. Call on page load.

Set passkey autofill on page load

Request to authenticate with passkey autofill on page load to initiate WebAuthn ceremony.

Client
    async function onPageLoad() {
        const nonce = await passage.passkey.authenticate({ isConditionalMediation: true });
    }

Add WebAuthn autofill attribute to identifier input

Provide an input for the autofill values to populate and give it an autocomplete="username webauthn" attribute. A button for standard authentication with identifier isn't necessary but is recommended as a fallback if passkey autofill isn't available.

index.html
<input autocomplete="username webauthn" id="authenticate-input" type="email" placeholder="you@example.com" />
<button id="authenticate-button" type="button" onclick="onAuthenticatePasskeyClick()">Log in</button>

Note: The autocomplete attribute supports multiple tokens, for passkey autofill to work webauthn must be the last token listed.

Authenticate user

Initialize a Passkey Flex instance using your app ID found in Passage Console (opens in a new tab). Passkey Flex triggers the WebAuthn (opens in a new tab) flow. Users are provided all app passkeys registered to the device.

Client
async function onLoginClick() {
    const nonce = await passage.passkey.authenticate();
    const authResult = // Result of request to example '/user/verify` endpoint with `nonce`
}

Learn more about the JavaScript SDK

Verify nonce & return auth identifier

From your server, verify the nonce with a Passkey Flex backend SDK.

Backend
app.post('/user/verify', async (req: Request, res: Response) => {
    const { nonce } = req.body;
 
    try {
        const externalId = await passage.verifyNonce(nonce);
 
        res.json({
            auth_token: 'auth_token_or_other_auth_solution',
        });
    } catch (err) {
        res.status(response.status).json({ error: 'Error' });
    }
});

Learn more about the Node SDK

Learn more