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

# Passkeys Post-Login Enrollment

> Seamless transition of password users to passwordless.

This feature allows users to enroll passkeys after they have successfully logged into the application using traditional authentication methods.

## Overview

The enrollment process consists of two main components:

1. **Step 1**: Obtain your Private Key
2. **Step 2**: Build an endpoint for JWT token generation
3. **Step 3**: Passkey enrollment via OwnID SDK

## Step 1 - Obtaining the Private Key

To generate the required RSA private key for JWT signing, follow these steps in the OwnID Console:

<Steps>
  <Step title="Navigate to Security Settings">
    In your OwnID Console, go to **Integration** > **Security** section for your application.
  </Step>

  <Step title="Generate Signing Key">
    Under the **Signing Key** section, click the **"Generate a new key"** button.

    <Warning>
      Generating a new RSA key pair will immediately invalidate any existing key. All requests currently using the old key will begin to return errors.
    </Warning>
  </Step>

  <Step title="Confirm Key Generation">
    A confirmation dialog will appear warning about key invalidation. Click **"Continue"** to proceed with generating the new key pair.
  </Step>

  <Step title="Copy Private Key">
    Once generated, a modal will display your new RSA private key. Copy the entire private key including the `-----BEGIN RSA PRIVATE KEY-----` and `-----END RSA PRIVATE KEY-----` markers.

    <Note>
      This is the only time you'll be able to view the private key. Store it securely!
    </Note>
  </Step>
</Steps>

## Step 2 - Backend Implementation

Implement a backend endpoint to generate a signed JWT enrollment token that authorizes the passkey enrollment session.

```javascript theme={null}
const createPasskeyEnrollmentToken = (userEmail, issuer) => {
  const now = Date.now();
  const iat = Math.floor(now / 1000);
  const exp = iat + 900; // 15 minutes
  const sessionExp = iat + 300; // 5 minutes for authorization_details

  const payload = {
    jti: require('crypto').randomUUID(),
    iat: iat,
    exp: exp,
    iss: `https://${issuer}`,
    aud: `https://${issuer}`,
    sub: `Email:${userEmail}`,
    authorization_details: [
      {
        type: "sessionCreation",
        iat: iat,
        exp: sessionExp
      }
    ]
  };

  const enrollmentToken = jwt.sign(payload, ownidSecretRSA, {
    algorithm: 'RS256',
    keyid: issuer
  });
  return { enrollmentToken };
}
```

**JWT Payload Structure**

<ResponseField name="jti" type="string" required>
  Unique token identifier
</ResponseField>

<ResponseField name="iat" type="number" required>
  Token issued at timestamp (Unix timestamp)
</ResponseField>

<ResponseField name="exp" type="number" required>
  Token expiration timestamp (15 minutes from iat)
</ResponseField>

<ResponseField name="iss" type="string" required>
  Issuer (website URL)
</ResponseField>

<ResponseField name="aud" type="string" required>
  Audience (same as issuer)
</ResponseField>

<ResponseField name="sub" type="string" required>
  Subject (user email with "Email:" prefix)
</ResponseField>

<ResponseField name="authorization_details" type="array" required>
  Session creation authorization details

  <Expandable title="Authorization Details Structure">
    <ResponseField name="type" type="string" required>
      Always "sessionCreation"
    </ResponseField>

    <ResponseField name="iat" type="number" required>
      Session issued at timestamp
    </ResponseField>

    <ResponseField name="exp" type="number" required>
      Session expiration timestamp (5 minutes from iat)
    </ResponseField>
  </Expandable>
</ResponseField>

## Step 3 - Frontend Implementation

<Info>
  * Ensure OwnID SDK is properly initialized with your application's configuration before calling the enrollment function.
  * We recommend you to trigger the Passkeys enrollment UI on the next page load after login.
</Info>

The frontend initiates passkey enrollment after obtaining the enrollment token:

```javascript theme={null}
const req = await this.authService.getPasskeyEnrollmentToken();
window.ownid('enrollCredential', req.enrollmentToken);
```

The UI is automatically managed by OwnID, both on mobile and desktop devices.

## Next Steps

### Ready to deploy?

<CardGroup cols={2}>
  <Card title="YES!" href="/building-blocks/pre-deployment-checklist" icon="rocket-launch">
    Take me to the Deployment Checklist
  </Card>

  <Card title="NOT YET..." href="/building-blocks/build-frontend-integration" icon="screwdriver-wrench">
    I want to build another user journey
  </Card>
</CardGroup>
