> ## Documentation Index
> Fetch the complete documentation index at: https://docs.authsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Using passkeys when integrating Authsignal with Amazon Cognito

> Learn how to use passkeys when integrating Authsignal with Amazon Cognito.

In the [previous guide](/integrations/aws-cognito/authenticators) we covered the integration steps required to let users enroll additional authentication methods - either using an **Authsignal Client SDK** or the **Authsignal pre-built UI**.

This guide will demonstrate how to use an **Authsignal Client SDK** to let the user create a passkey as an alternative authentication option which they can use for future sign-ins.

<Tip>
  This guide shows how to use passkeys with our React Native SDK, but you can just as easily use any
  of our [Mobile SDKs](/sdks/client/mobile/setup) for Swift, Kotlin, or Flutter, or our [Web
  SDK](/sdks/client/web/setup) for browser-based apps.
</Tip>

## Github example code

<CardGroup cols="2">
  <Card icon="github" horizontal title="Cognito lambdas" href="https://github.com/authsignal/cognito-lambdas" />

  <Card icon="github" horizontal title="React Native mobile app" href="https://github.com/authsignal/cognito-mobile-sms-example" />
</CardGroup>

## Creating a passkey

Once a user has signed in using their email address or phone number, we can prompt them to create a passkey to use for next time.

<Frame caption="Prompting the user to create a passkey after sign-in">
  <video controls className="w-full aspect-video" src="https://mintcdn.com/authsignal-23/8bvDamO56aVu-Ay2/images/docs/aws/create-passkey-mobile.mp4?fit=max&auto=format&n=8bvDamO56aVu-Ay2&q=85&s=92d6ee8c7a9f457833af814a27eeb944" data-path="images/docs/aws/create-passkey-mobile.mp4" />
</Frame>

### Lambda integration

To authorize binding the passkey to the user, we will create an authenticated endpoint which our app can call to obtain an Authsignal token.

This endpoint will use a [JWT Authorizer](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html) to authenticate using the Cognito access token.

```ts theme={null}
export const handler = async (event: APIGatewayProxyEventV2WithJWTAuthorizer) => {
  const claims = event.requestContext.authorizer.jwt.claims;
  const userId = claims.sub;

  const { token: authsignalToken } = await authsignal.track({
    userId,
    action: "addAuthenticator",
    attributes: {
      scope: "add:authenticators",
    },
  });

  return {
    authsignalToken,
  };
};
```

<Tip>
  The value we provide for `action` here will be used to keep track of these events in the
  Authsignal Portal.
</Tip>

### App integration

1. Call our endpoint to obtain a short-lived Authsignal token.

```ts theme={null}
// Replace with your API endpoint URL
const url = "https://abcd1234.execute-api.us-west-1.amazonaws.com/authenticators";

const authsignalToken = await fetch(url, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${cognitoAccessToken}`,
  },
})
  .then((res) => res.json())
  .then((json) => json.authsignalToken);
```

2. Set the Authsignal token using the React Native SDK.

```ts theme={null}
await authsignal.setToken(authsignalToken);
```

3. Create the passkey using the React Native SDK.

```ts theme={null}
// This can be the Cognito username (e.g email or phone number)
const username = "jane.smith@authsignal.com";

// This is an optional display name for the passkey
const displayName = "Jane Smith";

await authsignal.passkey.signUp({ username, displayName });
```

## Signing in with a passkey

Now that the user has created a passkey, the next time they sign in we can present them with the option to use their passkey.

<Frame caption="Using a passkey to sign in">
  <video controls className="w-full aspect-video" src="https://mintcdn.com/authsignal-23/8bvDamO56aVu-Ay2/images/docs/aws/sign-in-mobile.mp4?fit=max&auto=format&n=8bvDamO56aVu-Ay2&q=85&s=11809bf0957029783a9b8b56ec48caab" data-path="images/docs/aws/sign-in-mobile.mp4" />
</Frame>

### Lambda integration

No changes to our lambda code are required to handle passkeys as a sign-in method - our [verify auth challenge response lambda](/integrations/aws-cognito/getting-started#2-verify-auth-challenge-response) will validate the token which we pass as the challenge answer.

### App integration

In our React Native app we'll add some code to our sign-in screen to automatically show the passkey sign-in prompt if the user has one available on their device.

<CodeGroup>
  ```ts AWS SDK theme={null}
  async function signInWithPasskey() {
    // Show the passkey sign-in prompt
    const { data, errorCode } = await authsignal.passkey.signIn({
      action: "cognitoAuth",
    });

    // Exit if the user has no passkey available or if they dismissed the prompt
    if (errorCode === ErrorCode.user_canceled || errorCode === ErrorCode.no_credential) {
      return;
    }

    // Get the Cognito username associated with the passkey
    const username = data.username;

    // Get the Authsignal validation token
    const token = data.token;

    // Call InitiateAuth to obtain a session
    const initiateAuthCommand = new InitiateAuthCommand({
      ClientId: "YOUR_USER_POOL_CLIENT_ID",
      AuthFlow: AuthFlowType.CUSTOM_AUTH,
      AuthParameters: {
        USERNAME: username,
      },
    });

    const initiateAuthOutput = await client.send(initiateAuthCommand);

    const session = initiateAuthOutput.Session;

    // Call RespondToAuthChallenge and pass the Authsignal validation token
    const respondToAuthChallengeCommand = new RespondToAuthChallengeCommand({
      ClientId: "YOUR_USER_POOL_CLIENT_ID",
      ChallengeName: ChallengeNameType.CUSTOM_CHALLENGE,
      Session: session,
      ChallengeResponses: {
        USERNAME: username,
        ANSWER: token,
      },
    });

    const respondToAuthChallengeOutput = await cognito.send(initiateAuthCommand);

    // Obtain the Cognito access token and complete sign-in
    const accessToken = respondToAuthChallengeOutput.AuthenticationResult?.AccessToken;
  }
  ```

  ```ts Amplify theme={null}
  async function signInWithPasskey() {
    // Show the passkey sign-in prompt
    const { data, errorCode } = await authsignal.passkey.signIn({
      action: "cognitoAuth",
    });

    // Exit if the user has no passkey available or if they dismissed the prompt
    if (errorCode === ErrorCode.user_canceled || errorCode === ErrorCode.no_credential) {
      return;
    }

    // Get the Cognito username associated with the passkey
    const username = data.username;

    // Get the Authsignal validation token
    const token = data.token;

    // Call InitiateAuth
    await signIn({
      username: username,
      options: {
        authFlowType: "CUSTOM_WITHOUT_SRP",
      },
    });

    // Call RespondToAuthChallenge and pass the Authsignal validation token
    await confirmSignIn({
      challengeResponse: token,
    });
  }
  ```
</CodeGroup>

Then finally we'll run this function in a `useEffect` hook when our sign-in screen first appears.

```ts theme={null}
useEffect(() => {
  signInWithPasskey();
}, []);
```

## Next steps

* [Uber app example](/integrations/aws-cognito/example-app)
* [Adaptive MFA](/integrations/aws-cognito/rules)
