1. Introduction
Corbado Connect allows you to seamlessly integrate passkey-first authentication into your existing Amazon Cognito user pools. This enables you to offer your users a secure and convenient login experience without passwords, while still leveraging the power of Cognito for user management. This guide will walk you through the process of integrating Corbado Connect with Amazon Cognito, using a sample Next.js application to demonstrate the key concepts. Amazon Cognito is a service that provides authentication, authorization, and user management for your web and mobile apps. You can learn more about it on the official Amazon Cognito website.2. How it Works
The integration between Corbado Connect and Amazon Cognito leverages a powerful feature known as a Custom Authentication Flow. This feature allows developers to create their own challenge-and-response models using AWS Lambda functions, which is ideal for integrating external authentication mechanisms like Corbado’s passkey-first solution. Instead of a traditional username and password, we will define a custom flow that uses a passkey signature as the challenge. To implement this, we need to configure the Cognito User Pool to use three specific AWS Lambda triggers:define_auth_challenge
: This Lambda acts as the orchestrator of our custom flow. It determines which challenge to present to the user at each step of the authentication process.create_auth_challenge
: This Lambda is responsible for creating the challenge itself. In our case, it won’t be creating a secret, but rather preparing for the verification that happens in the next step.verify_auth_challenge_response
: This is where the core verification logic resides. This Lambda takes the signed passkey data from the frontend (provided by Corbado Connect), and verifies it against Corbado’s Backend API to confirm the user’s identity. If verification is successful, it informs Cognito to issue the session tokens.
3. Example Application
To best illustrate the integration, we will refer to a complete example application. This application is built with the following technologies:- Next.js: A popular React framework for building server-rendered applications.
- AWS Amplify: A library that simplifies interacting with AWS services like Cognito from a frontend application.
4. User Sign-up
In our example application, the initial user sign-up is handled through a conventional method (e.g., email and password) managed by Amazon Cognito. Once the user has an account and is logged in, we offer them the option to add a passkey to their account for future passwordless logins. This process is often called “passkey append”. The complete flow is illustrated in detail here.4.1 Implementation Overview
The user sign-up process consists of a series of interactions between the example application (utilizing AWS Amplify), Amazon Cognito, and Corbado APIs. These interactions are best illustrated using a sequence diagram: In the following sections, we will explain each step in detail.4.2 Web UI Component Integration
We start by integrating the CorbadoConnectAppend component from the@corbado/connect-react
library. The component takes care of the entire UI and logic for creating and storing the passkey.
Here’s how it’s used in our example application’s post-login
page:
/application/cognito/app/(auth-required)/post-login/page.tsx
For a detailed explanation of all available props for this component, please see the CorbadoConnectAppend component documentation.
4.3 Obtaining the Connect Token
When the component is initialized, it executes the function given inappendTokenProvider
to request a connect token from Corbado’s Backend API (this token authorizes the creation of a passkey for a specific and authenticated user).
The frontend first needs to get the idToken
for the currently logged-in user from AWS Amplify. This JWT is proof of the user’s session with Amazon Cognito. The idToken
is then sent to a Next.js Server Action:
idToken
to ensure it’s valid and extracts the user’s identity, then requests the connect token by calling the utility function getCorbadoConnectToken()
:
/application/cognito/app/(auth-required)/post-login/actions.ts
4.4 Updating MFA Settings
After a passkey is created, it’s necessary to update the MFA settings in Amazon Cognito. This can be achieved using Corbado actions, which enable you to extensively customize Corbado Connect to suit your specific requirements. Thepost-append
action utilizes the AdminGetUser
command from Amazon Cognito to verify if MFA is already configured. If it is not, the AdminSetUserMFAPreference
command is executed to update the settings:
index.mjs
5. User Login
Now that users can associate passkeys with their accounts, we can enable a truly passwordless login experience. This is where the Amazon Cognito custom authentication flow we outlined in the “How it Works” section becomes essential. The goal is to authenticate a user with their passkey using Corbado Connect and, upon success, establish an authenticated session with Amazon Cognito. To achieve this, we will use our three custom AWS Lambda functions to bridge the gap between the two systems and ultimately receive valid session tokens from Amazon Cognito. The complete flow is illustrated in detail here.5.1 Implementation Overview
The user login process consists of a series of interactions between the example application (utilizing AWS Amplify), Amazon Cognito, Lambda functions, and Corbado APIs. These interactions are best illustrated using a sequence diagram:The signedPasskeyData proves a successful passkey authentication with Corbado. It is the key artifact that connects the two systems.
5.2 Web UI Component Integration
Again, we start by integrating the CorbadoConnectLogin component from the@corbado/connect-react
library. The component takes care of the entire UI and logic for handling the passkey login and passing the result to our application logic to complete the login with Amazon Cognito.
The core logic resides in a client component that wraps the CorbadoConnectLogin component:
/application/cognito/app/login/WrappedLogin.tsx
For a detailed explanation of all available props for this component, please see the CorbadoConnectLogin component documentation.
onComplete
handler triggers our postPasskeyLoginNew
function, which performs the final steps to log the user into Cognito:
- Decode the JWT: The signedPasskeyData is a JWT. We decode it to extract the
webauthnId
, which is a stable identifier for the user in Corbado’s system. We will use this as theusername
for Amazon Cognito’s custom flow. signIn
: We callsignIn
from the AWS Amplify library, passing thewebauthnId
as theusername
and specifyingauthFlowType: 'CUSTOM_WITHOUT_SRP'
. This initiates the custom authentication flow and triggers ourdefine_auth_challenge
andcreate_auth_challenge
Lambdas.confirmSignIn
: We then immediately callconfirmSignIn
, providing the entire signedPasskeyData as thechallengeResponse
. This is the answer to the custom challenge, which triggers ourverify_auth_challenge_response
Lambda.- Redirection: Once
confirmSignIn
completes successfully, Amazon Cognito has issued valid session tokens to the Amplify library. The user is now fully authenticated, and we can redirect them to a protected page, like their profile.
5.3 Identifier Translation
Since Corbado Connect only stores the Amazon Cognito username and not the user’s email address, we need to translate between these identifiers during login. This translation is handled through Corbado actions, which provide extensive customization capabilities for Corbado Connect to meet your specific requirements. Thepre-login
action utilizes the AdminGetUser
command from Amazon Cognito to search for a user by their email address and return the corresponding Amazon Cognito username to Corbado Connect:
index.mjs
5.4 Custom Lambda functions
As introduced in the “How it Works” section, the integration between Corbado Connect and Amazon Cognito relies on three custom Lambda functions to handle the authentication flow. These functions work together to verify passkey authentications and manage the challenge-response cycle in Amazon Cognito. Let’s dive deeper into each function’s implementation and configuration.5.4.1 Secrets
Our custom Lambda functions need to communicate securely with Corbado’s Backend API. To do this, they require access to sensitive credentials, namely your Project ID and API Secret. It is critical to never hard-code secrets directly into your Lambda function’s source code. Instead, you should use a dedicated service for managing secrets. For our example application, and as a recommended best practice, we use AWS Systems Manager (SSM) Parameter Store. By storing credentials asSecureString
parameters in the SSM Parameter Store, you ensure that they are encrypted at rest. You can then grant the Lambda function’s IAM role the necessary permissions to read these specific parameters at runtime. This approach provides a secure and scalable way to manage your secrets, separating them from your application code.
5.4.2 Implementation
Here we will examine the code for each of the three Lambda functions required for the custom authentication flow.This is the first and last Lambda to be called in the flow. It acts as the orchestrator or state machine.
index.mjs
You need to configure these three Lambdas in your Amazon Cognito User Pool’s settings under User pool > Authentication > Extensions.
5.4.3 Hosting
The three custom authentication Lambda functions can be deployed in two different ways, depending on your chosen setup and requirements:- Corbado-Hosted: For ease of use and quicker setup, Corbado can manage and host these Lambda functions on your behalf within our secure AWS environment. This model simplifies maintenance and operations.
- Self-Hosted: For organizations that require full control over their infrastructure for security, compliance, or customization reasons, you can deploy and manage these Lambda functions directly within your own AWS account.
6. Passkey Management
After users have created their initial passkeys during sign-up and used them for login, they need a way to manage their existing passkeys. Passkey management encompasses three main operations:- Viewing existing passkeys
- Creating additional passkeys
- Deleting unused passkeys
6.1 Implementation Overview
The passkey deletion process consists of a series of interactions between the example application (utilizing AWS Amplify), Amazon Cognito, and Corbado APIs. These interactions are best illustrated using a sequence diagram:6.2 Web UI Component Integration
We integrate the CorbadoConnectPasskeyList component from the@corbado/connect-react
library. This component provides a complete user interface for managing passkeys, including viewing, adding, and deleting them.
Here’s how it’s used in our example application’s profile page:
/application/cognito/app/(auth-required)/profile/PasskeySection.tsx
For a detailed explanation of all available props for this component, please see the CorbadoConnectPasskeyList component documentation.
6.3 Obtaining the Connect Token
When the component needs to perform an operation (like deleting a passkey), it executes the function given inconnectTokenProvider
to request a connect token from Corbado’s Backend API. This token authorizes the specific operation for the authenticated user.
The frontend first gets the idToken
for the currently logged-in user from AWS Amplify. This JWT proves the user’s session with Amazon Cognito. The idToken
is then sent to a Next.js Server Action:
idToken
to ensure it’s valid and extracts the user’s identity, then requests the connect token by calling the utility function getCorbadoConnectToken()
:
/application/cognito/app/(auth-required)/profile/actions.tsx
connectTokenType
to specify which operation the token should authorize (in this case, it could be ‘passkey-list’, ‘passkey-add’, or ‘passkey-delete’).