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

# Web Application Integration with Corbado Connect

> Learn how to integrate passkey authentication into your web application using the Corbado Web UI Components. This guide covers setup, passkey enrollment, login, and management.

<Columns cols={3}>
  <Card href="https://cognito.cloud.corbado-demo.com">
    Try Demo
  </Card>

  <Card href="https://calendly.com/vincent-delitz">
    Talk to Adoption Engineer
  </Card>

  <Card href="https://www.corbado.com/passkeys/enterprise">
    Whitepaper
  </Card>
</Columns>

## 1. Introduction

**Corbado Connect** provides a set of Web UI Components that simplify the integration of passkey authentication into your web application. By using our components, you can offer a seamless and secure user experience with passkeys, without needing to replace your existing Identity Provider (IdP). The components handle the complexities of the WebAuthn standard and our backend APIs, allowing you to focus on your web application's core functionality.

This guide provides a step-by-step approach to integrating the **Corbado Connect Web UI Components**. You'll learn how to implement passkey enrollment, login, and management within your web application.

## 2. Backend Integration

The backend logic required to support **Corbado Connect** is consistent across all client platforms, whether it's a web application or a native/mobile application.

To maintain a single source of truth and avoid duplicating instructions, we've consolidated all backend-related steps into a dedicated guide. Please refer to it for a complete walkthrough of the required session management and API endpoints in your backend:

<Card title="Backend Setup" href="/corbado-connect/integration/generic/backend">
  Learn how to implement the necessary session management and API endpoints in your backend.
</Card>

<Warning>
  For simplicity in the following sections, we will store the **access token** in local storage. Please be aware that this is not a recommended practice for production environments. Storing **access tokens** in local storage makes them vulnerable to Cross-Site Scripting (XSS) attacks, where an attacker could steal the token. Secure token storage depends on the specific use case and is beyond the scope of this article.
</Warning>

## 3. Passkey Enrollment

In a typical integration scenario, the initial user sign-up is handled through your existing authentication system's standard registration process. This could be through:

* Email and password registration
* Social login providers
* Enterprise SSO

Once a user has successfully created an account and is logged in, **Corbado Connect** provides the ability to add a passkey to their account for future passwordless logins. This process is often called "passkey append" and represents the bridge between your existing user management system and Corbado's passkey infrastructure.

This approach offers several advantages:

* Maintains compatibility with your existing user registration flow
* Allows for gradual adoption of passkeys
* Preserves existing user data and relationships
* Enables a smooth transition for your users

The complete user sign-up and passkey append flow is illustrated in detail in our [User Sign-up Flow documentation](/corbado-connect/flows/user-sign-up). In the following sections, we'll break down each component of the implementation.

### 3.1 Implementation Overview

The user sign-up and passkey append process consists of a series of coordinated interactions between your application's frontend and backend, your authentication system, and Corbado's APIs. Here's a high-level overview of the flow:

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant Frontend as Your<br/>Frontend
    participant Backend as Your<br/>Backend
    participant IdP as Your<br/>Auth System
    participant FAPI as Corbado<br/>Frontend API
    participant BAPI as Corbado<br/>Backend API
    participant Actions as Corbado<br/>Actions

    Note over Frontend: CorbadoConnectAppend component<br/>initiates
    Frontend->>+Backend: POST /auth/createConnectToken
    Backend->>Backend: Verify access token of user
    Backend->>+BAPI: POST /v2/connectTokens
    BAPI-->>-Backend: Return connect token
    Backend-->>-Frontend: Return connect token

    Frontend->>+FAPI: Execute passkey ceremony (WebAuthn)
    Note over Frontend: CorbadoConnectAppend component<br/>handles passkey creation
    FAPI->>+Actions: Execute post-append action
    Actions->>+IdP: Set user preferences/flags
    IdP-->>-Actions: Return success
    Actions-->>-FAPI: Return success
    FAPI-->>-Frontend: Return success
```

<Info>For more details on **access tokens**, please refer to the session management section in the [Backend Setup](/corbado-connect/integration/generic/backend#2-session-management) guide.</Info>

In the following sections, we will explain each step in detail.

### 3.2 Web UI Component Integration

The integration starts with the [CorbadoConnectAppend](/corbado-connect/web-ui-components/corbadoconnectappend) component, which is designed to be used immediately after a user has been authenticated through your existing system. The component guides users through creating (or "appending") a passkey to their account, but only if they and their device meet the eligibility requirements.

Here's an example integration:

```html theme={null}
<head>
  <script src="https://cdn.cloud.corbado.io/connect/dist/web-js-latest.min.js"></script>
  <link rel="stylesheet" href="https://cdn.cloud.corbado.io/connect/dist/web-js-latest.min.css" />
  <script type="module">
    const passkeyAppendElement = document.getElementById('passkey-append');
    Corbado.mountCorbadoConnectAppend(passkeyAppendElement, {
      projectId: "pro-XXX", // Your Corbado Project ID
      frontendApiUrlSuffix: "frontendapi.cloud.corbado.io",

      // Called when the user decides not to create a passkey or passkey creation
      // is skipped. Add custom logic like logging and analytics.
      onSkip: (status) => { 
        console.log('Append skipped with status:', status);
      },

      appendTokenProvider: async () => {
        // 1. Get access token from local storage
        const accessToken = localStorage.getItem('accessToken');
        if (!accessToken) {
            throw new Error('User not authenticated');
        }

        // 2. Get connect token from your backend (see next section)
        const response = await fetch('/auth/createConnectToken', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${accessToken}`
            },
            body: JSON.stringify({
                connectTokenType: 'passkey-append',
            })
        });

        if (!response.ok) {
            throw new Error('Failed to get connect token');
        }

        const data = await response.json();

        return data.connectToken;
      },

      // Called when passkey creation is completed successfully. Use to
      // refresh page or show success UI for example.
      onComplete: (status, clientState) => { 
        console.log('Append complete with status:', status);
      },
    });
  </script>
</head>

<body>
  <!-- The passkey append UI will render into this div -->
  <div id="passkey-append"></div>
</body>
```

<Info>
  For comprehensive information on configuration options, detailed styling choices, and customization using CSS variables and classes, please refer to the [CorbadoConnectAppend](/corbado-connect/web-ui-components/corbadoconnectappend) component documentation.
</Info>

### 3.3 Obtaining the Connect Token

When the component is initialized, it executes the function given in `appendTokenProvider` to request a [connect token](/corbado-connect/concepts/connect-token) from your backend.

For detailed instructions on how to implement the required endpoint in your backend, please refer to our [Backend Setup guide](/corbado-connect/integration/generic/backend).

<Info>
  Always generate a new token for each passkey operation.
</Info>

### 3.4 Updating MFA Settings

After a passkey is created, you may need to update settings in your authentication system to reflect this change. This could include:

* Marking the user as having MFA enabled
* Setting passkey as the preferred authentication method
* Updating user preferences or flags
* Recording the passkey creation timestamp

This can be achieved using Corbado [actions](/corbado-connect/architecture/actions), which enable you to extensively customize **Corbado Connect** to suit your specific requirements.

The `post-append` action is triggered after successful passkey creation. Here's an example of how you might implement this action:

```javascript theme={null}
// Main handler function
export const handler = async (event) => {
    console.log('Received event:', event);

    try {
        const username = event.username;
        
        // 1. Check if MFA settings are already configured
        const user = await yourAuthSystem.getUser(username);
        if (user.hasMfaEnabled) {
            console.log('User already has MFA settings configured');
            
            return {
                statusCode: 200,
                body: {},
            };
        }

        // 2. Update MFA settings in your authentication system
        await yourAuthSystem.updateUser(username, {
            mfaEnabled: true,
            preferredMfaMethod: 'passkey',
            lastMfaUpdate: new Date().toISOString()
        });

        // 3. Return success
        return {
            statusCode: 200,
            body: {}
        };
    } catch (error) {
        console.error('Caught exception:', error);

        return {
            statusCode: 500,
            body: {
                message: 'Failed to update MFA settings',
                error: error.message,
            },
        };
    }
};
```

The exact implementation will depend on your authentication system's API or SDK, but the general flow remains the same:

1. Receive the event with user information from Corbado
2. Connect to your authentication system
3. Check current MFA settings (optional)
4. Update the settings as needed
5. Return success or error response

<Info>
  For more information about Corbado actions and how to implement them, see the [Actions documentation](/corbado-connect/architecture/actions).
</Info>

## 4. Passkey Login

Now that users can associate passkeys with their accounts, we can enable a truly passwordless login experience. The goal is to authenticate a user with their passkey using **Corbado Connect** and, upon successful verification, obtain a new **access token** from your system.

The complete flow is illustrated in detail in our [User Login Flow documentation](/corbado-connect/flows/user-login).

### 4.1 Implementation Overview

The cornerstone of user login integration is [signedPasskeyData](/corbado-connect/concepts/signed-passkey-data) (option 1 & 2). This token acts as the link between **Corbado Connect's** passkey authentication and your authentication system, which ultimately needs to create an **access token**.

There are several ways to integrate the passkey login flow with your authentication system:

1. **System Extension**: If your authentication system supports plugins or custom authentication methods, you can extend it to manage [signedPasskeyData](/corbado-connect/concepts/signed-passkey-data) verification and **access token** creation (refer to our [Amazon Cognito](/corbado-connect/integration/cognito) integration guide, which follows this approach).
2. **Custom Endpoint**: Develop a new endpoint in your backend that verifies [signedPasskeyData](/corbado-connect/concepts/signed-passkey-data) and create an **access token**.
3. **Corbado Action**: Utilize Corbado's action system to directly manage the authentication flow and create an **access token**.

In each option, it is necessary to create an **access token** within your authentication system at the conclusion of the process.

<Info>For more details on **access tokens**, please refer to the session management section in the [Backend Setup](/corbado-connect/integration/generic/backend#2-session-management) guide.</Info>

We will now elaborate on each option in the following sections.

#### 4.1.1 Option 1: System Extension

This option involves extending your existing authentication system through its plugin architecture or custom authentication method support. Many modern authentication systems provide ways to add new authentication methods or customize the authentication flow.

Here's how the flow typically works:

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant Frontend as Your<br/>Frontend
    participant IdP as Your<br/>Auth System
    participant Plugin as Your Auth System<br/>Plugin/Extension
    participant FAPI as Corbado<br/>Frontend API
    participant BAPI as Corbado<br/>Backend API
    participant Actions as Corbado<br/>Actions

    Frontend->>+FAPI: Execute passkey ceremony (WebAuthn)
    Note over Frontend: CorbadoConnectLogin component<br/>handles passkey login
    FAPI->>+Actions: Execute pre-login action
    Actions->>+IdP: User lookup by email
    IdP-->>-Actions: Return user ID
    Actions-->>-FAPI: Return user ID
    FAPI->>FAPI: Verify passkey login
    FAPI-->>-Frontend: Return signedPasskeyData

    Frontend->>+IdP: Login with signedPasskeyData
    IdP->>+Plugin: Handle passkey authentication
    Plugin->>+BAPI: POST /v2/passkeys/verifySignedData
    BAPI-->>-Plugin: Return verification result
    Plugin-->>-IdP: Return verification success
    IdP->>IdP: Create access token
    IdP-->>-Frontend: Return access token
```

This approach is ideal when:

* Your authentication system has a plugin architecture
* You want to maintain all authentication logic within your existing system
* You need tight integration with your system's session/token management
* You want to leverage your system's existing user management features

<Info>
  The exact implementation details will depend on your authentication system's extension capabilities. Some systems might require implementing specific interfaces or following certain patterns.
</Info>

#### 4.1.2 Option 2: Custom Endpoint

This option involves implementing a dedicated endpoint in your backend that handles passkey verification and **access token** creation. This approach gives you full control over the authentication flow and is suitable when your authentication system doesn't support extensions or when you need custom session/token handling.

Here's how the flow typically works:

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant Frontend as Your<br/>Frontend
    participant Backend as Your<br/>Backend
    participant IdP as Your<br/>Auth System
    participant FAPI as Corbado<br/>Frontend API
    participant BAPI as Corbado<br/>Backend API
    participant Actions as Corbado<br/>Actions

    Frontend->>+FAPI: Execute passkey ceremony (WebAuthn)
    Note over Frontend: CorbadoConnectLogin component<br/>handles passkey login
    FAPI->>+Actions: Execute pre-login action
    Actions->>+IdP: User lookup by email
    IdP-->>-Actions: Return user ID
    Actions-->>-FAPI: Return user ID
    FAPI->>FAPI: Verify passkey login
    FAPI-->>-Frontend: Return signedPasskeyData

    Frontend->>+Backend: POST /auth/completeLogin<br/>(signedPasskeyData)
    Backend->>+BAPI: POST /v2/passkeys/verifySignedData
    BAPI-->>-Backend: Return verification result
    Backend->>+IdP: Create access token
    IdP-->>-Backend: Return access token
    Backend-->>-Frontend: Return access token
```

The implementation involves creating a new endpoint in your backend that receives the [signedPasskeyData](/corbado-connect/concepts/signed-passkey-data), verifies it by calling Corbado's Backend API, and then obtains an **access token** from your own authentication system.

For detailed instructions on how to implement this endpoint, please refer to our [Backend Setup guide](/corbado-connect/integration/generic/backend).

This approach is ideal when:

* Your authentication system doesn't support plugins/extensions
* You need complete control over the authentication flow
* You want to implement custom session/token management
* You're building a new authentication system from scratch

<Info>
  Remember to implement proper error handling and security measures in your endpoint, such as rate limiting and logging.
</Info>

#### 4.1.3 Option 3: Corbado Action

This option leverages Corbado's action system to handle the authentication flow. Instead of implementing verification logic of [signedPasskeyData](/corbado-connect/concepts/signed-passkey-data) in your system, you can use a `post-login` action to create and return an **access token**. This approach minimizes the integration effort while maintaining security.

Here's how the flow typically works:

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant Frontend as Your<br/>Frontend
    participant IdP as Your<br/>Auth System
    participant FAPI as Corbado<br/>Frontend API
    participant BAPI as Corbado<br/>Backend API
    participant Actions as Corbado<br/>Actions

    Frontend->>+FAPI: Execute passkey ceremony (WebAuthn)
    Note over Frontend: CorbadoConnectLogin component<br/>handles passkey login
    FAPI->>+Actions: Execute pre-login action
    Actions->>+IdP: User lookup by email
    IdP-->>-Actions: Return user ID
    Actions-->>-FAPI: Return user ID
    FAPI->>FAPI: Verify passkey login
    FAPI->>+Actions: Execute post-login action
    Actions->>+IdP: Create access token
    IdP-->>-Actions: Return access token
    Actions-->>-FAPI: Return access token
    FAPI-->>-Frontend: Return access token
```

The implementation involves creating a `post-login` action:

```javascript theme={null}
export const handler = async (event) => {
    console.log('Received event:', event);

    try {
        const userId = event.userId;

        // 1. Create access token in your auth system
        const accessToken = await yourAuthSystem.createAccessToken({
            userId: userId,
        });

        // 2. Return access token to the client
        return {
            statusCode: 200,
            body: {
                accessToken: accessToken
            }
        };
    } catch (error) {
        console.error('access token creation failed:', error);

        return {
            statusCode: 500,
            body: {
                message: 'Failed to create access token',
                error: error.message,
            },
        };
    }
};
```

This approach is ideal when:

* You want minimal changes to your existing system
* You prefer to handle authentication logic in **Corbado Connect's** environment
* You need a quick integration path
* Your authentication system has a simple session/token creation API

<Info>
  The action environment provides secure access to your authentication system's API. Make sure to configure the necessary credentials and permissions in your **Corbado Connect** project settings.
</Info>

### 4.2 Web UI Component Integration

The integration starts with the [CorbadoConnectLogin](/corbado-connect/web-ui-components/corbadoconnectlogin) component. 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.

Here's an example integration:

```html theme={null}
<head>
  <script src="https://cdn.cloud.corbado.io/connect/dist/web-js-latest.min.js"></script>
  <link rel="stylesheet" href="https://cdn.cloud.corbado.io/connect/dist/web-js-latest.min.css" />

  <script type="module">
    const passkeyLoginElement = document.getElementById('authorize-with-passkey');
    Corbado.mountCorbadoConnectLogin(passkeyLoginElement, {
      projectId: "pro-XXX", // Your Corbado Project ID
      frontendApiUrlSuffix: "frontendapi.cloud.corbado.io", // Points to your chosen Corbado Frontend API environment

      // Called when passkey login is completed successfully
      onComplete: (signedPasskeyData, clientState) => {
        // This callback varies depending on the option chosen; see the following sections for details
      },

      // Called when passkey login is not possible or fails critically. Show your
      // fallback UI (e.g., a password field). The identifier might be pre-filled if
      // the user provided one.
      onFallback: (identifier, errorMessage) => {
        console.log(`Fallback triggered for '${identifier}' with message: ${errorMessage}`);
      },
    });
  </script>
</head>

<body>
  <div id="authorize-with-passkey"></div>
  <div id="authorize-with-fallback" style="display: none;">
    <!-- Your existing fallback authentication (e.g. password) comes here -->
  </div>
</body>
```

<Info>
  For comprehensive information on configuration options, detailed styling choices, and customization using CSS variables and classes, please refer to the [CorbadoConnectLogin](/corbado-connect/web-ui-components/corbadoconnectlogin) component documentation.
</Info>

The implementation details for the `onComplete` callback will be provided in the subsequent sections.

#### 4.2.1 Option 1: System Extension

As we have integrated with the existing authentication system, **access token** creation and storage are managed by it. Therefore, after a successful passkey login, we need to hand over to the existing authentication system to complete the login:

```javascript theme={null}
onComplete: (signedPasskeyData, clientState) => {
    handlePasskeyLogin(signedPasskeyData);
}
```

#### 4.2.2 Option 2: Custom Endpoint

When using the custom endpoint approach, the `onComplete` callback needs to send the [signedPasskeyData](/corbado-connect/concepts/signed-passkey-data) to your verification endpoint and redirect to the profile page:

```javascript theme={null}
onComplete: async (signedPasskeyData, clientState) => {
    // 1. Send signedPasskeyData to your verification endpoint
    const response = await fetch('/auth/completeLogin', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ signedPasskeyData })
    });

    if (!response.ok) {
        throw new Error('Verification failed');
    }

    // 2. The backend returns an access token, store it
    const { success, accessToken } = await response.json();
    if (success) {
        localStorage.setItem('accessToken', accessToken);

        // 3. Redirect to profile page
        window.location.href = '/profile';
    } else {
        throw new Error('Login failed');
    }
}
```

#### 4.2.3 Option 3: Corbado Action

When using a Corbado Action, the **access token** is returned directly in the `result` object, simplifying the frontend logic:

```javascript theme={null}
onComplete: async (result, clientState) => {
    const { accessToken } = result;

    // 1. Store the access token in local storage
    localStorage.setItem('accessToken', accessToken);

    // 2. Redirect to profile page
    window.location.href = '/profile';
}
```

## 5. Passkey Management

Providing users with a way to manage their passkeys is a critical part of the experience. The [CorbadoConnectPasskeyList](/corbado-connect/web-ui-components/corbadoconnectpasskeylist) component offers a complete, pre-built UI for users to list, add, and delete passkeys associated with their account.

This component should be placed in a secure, authenticated area of your application, such as a user profile or account settings page.

### 5.1 Implementation Overview

The [CorbadoConnectPasskeyList](/corbado-connect/web-ui-components/corbadoconnectpasskeylist) component requires a distinct [connect token](/corbado-connect/concepts/connect-token) to perform each of its actions. Much like the enrollment flow, these tokens must be securely fetched from your backend to authorize each specific operation for the logged-in user.

### 5.2 Web UI Component Integration

Integrate the [CorbadoConnectPasskeyList](/corbado-connect/web-ui-components/corbadoconnectpasskeylist) component on a profile or settings page. The component will handle all the logic for displaying passkeys and managing user interactions:

```html theme={null}
<head>
  <script src="https://cdn.cloud.corbado.io/connect/dist/web-js-latest.min.js"></script>
  <link rel="stylesheet" href="https://cdn.cloud.corbado.io/connect/dist/web-js-latest.min.css" />

  <script type="module">
    const passkeyListElement = document.getElementById('passkey-list');

    // This function provides connect tokens for all actions (list, append, delete)
    const connectTokenProvider = async (type) => {
      // 'type' will be 'passkey-list', 'passkey-append', or 'passkey-delete'

      // 1. Get access token from local storage
      const accessToken = localStorage.getItem('accessToken');
      if (!accessToken) {
        throw new Error('User not authenticated');
      }

      // 2. Get connect token from your backend
      const response = await fetch('/auth/createConnectToken', {
        method: 'POST',
        headers: { 
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${accessToken}`
        },
        body: JSON.stringify({ connectTokenType: type }), 
      });

      if (!response.ok) {
        throw new Error(`Failed to get connect token for type: ${type}`);
      }

      const { connectToken } = await response.json();

      return connectToken;
    };

    Corbado.mountCorbadoConnectPasskeyList(passkeyListElement, {
      projectId: "pro-XXX", // Your Corbado Project ID
      frontendApiUrlSuffix: "frontendapi.cloud.corbado.io",
      connectTokenProvider: connectTokenProvider
    });
  </script>
</head>

<body>
  <!-- The passkey list UI will render into this div -->
  <div id="passkey-list"></div>
</body>
```

<Info>
  For a detailed explanation of all available props and customization options, please see the [CorbadoConnectPasskeyList](/corbado-connect/web-ui-components/corbadoconnectpasskeylist) component documentation.
</Info>

### 5.3 Obtaining the Connect Token

The `connectTokenProvider` function is the bridge to your backend. It's responsible for fetching a [connect token](/corbado-connect/concepts/connect-token) from your backend for the specific action (`passkey-list`, `passkey-append`, or `passkey-delete`) the user wants to perform. The implementation of this endpoint is described in our [Backend Setup guide](/corbado-connect/integration/generic/backend).

When a user opens the page, the component will call `connectTokenProvider('passkey-list')` to get a token to display the existing passkeys. If they try to delete a passkey, it will call `connectTokenProvider('passkey-delete')`, and so on. This ensures every action is explicitly authorized by your backend for the currently authenticated user.
