PasskeyBase

Enrollment

Add passkey authentication to your existing auth system. Users can enroll passkeys while already logged in, then use those passkeys for future logins.


How It Works

Enrollment lets you bridge your existing authentication system with PasskeyBase. The flow works in two parts:

  1. Server-side: Your backend creates an enrollment token via the Management API, linking your existing user ID.
  2. Client-side: The SDK opens a popup where the user creates a passkey. No redirect -- the user stays on your page.
Enrollment Popup Flow
myapp.com/dashboardYour App PageAdd Passkey1pb.enrollPasskey(token)2Waiting for popup...Passkey enrolled!6Promise resolves with credentialmyapp.auth.ing/enrollPasskeyBaseCreate a passkeyfor myapp.comCreate Passkey3🔒WebAuthn PromptFace ID / Touch ID4Success! Popup closes.5opens popuppostMessage

Step 1: Create an Enrollment Token (Server)

From your backend, call the PasskeyBase Management API to create a one-time enrollment token. You must provide your user's existing ID as the external_id. This links the PasskeyBase identity to your user.

Security: Always create enrollment tokens on your server. Never expose your Management API key to the frontend.

Server-side token creation
// Server-side: Create an enrollment token
// POST https://myapp.auth.ing/api/v1/enrollment-tokens

const response = await fetch('https://myapp.auth.ing/api/v1/enrollment-tokens', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_MANAGEMENT_API_KEY',
  },
  body: JSON.stringify({
    external_id: 'user_123',           // Your existing user ID
    display_name: 'Jane Doe',          // Optional display name
    expires_in: 3600,                  // Token TTL in seconds (default: 1 hour)
  }),
});

const { token } = await response.json();
// token: "enroll_tok_abc123..."
// Return this token to your frontend

Step 2: Enroll Passkey (Frontend)

Pass the enrollment token to the SDK's enrollPasskey()method. It opens a popup window where the user creates a passkey.

Frontend enrollment
// Frontend: Enroll a passkey for the logged-in user
import { PasskeyBase } from '@passkeybase/js';

const pb = new PasskeyBase({
  clientId: 'pk_live_abc123',
  domain: 'myapp.auth.ing',
});

// Get the enrollment token from your backend
const response = await fetch('/api/enrollment-token', {
  method: 'POST',
  headers: { 'Authorization': 'Bearer ' + sessionToken },
});
const { token } = await response.json();

// Open the enrollment popup
try {
  await pb.enrollPasskey(token);
  console.log('Passkey enrolled successfully!');
  showSuccessMessage('You can now log in with your passkey.');
} catch (err) {
  if (err.message === 'popup_closed') {
    console.log('User closed the enrollment popup');
  } else {
    console.error('Enrollment failed:', err);
  }
}

Full Example: Express.js Backend

Here is a complete example of creating an enrollment endpoint in an Express.js app:

server.js
// Express.js example
const express = require('express');
const app = express();

app.post('/api/enrollment-token', requireAuth, async (req, res) => {
  const user = req.user; // From your existing auth middleware

  const response = await fetch(
    'https://myapp.auth.ing/api/v1/enrollment-tokens',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.PASSKEYBASE_API_KEY}`,
      },
      body: JSON.stringify({
        external_id: user.id,
        display_name: user.name,
      }),
    }
  );

  const data = await response.json();
  res.json({ token: data.token });
});

After Enrollment

Once a user has enrolled a passkey, they can authenticate using the standard OAuth flow (via loginWithRedirect()). The ID token will include the external_idyou provided during enrollment, so you can map the PasskeyBase identity back to your existing user.

Multiple Passkeys

Users can enroll multiple passkeys (e.g., one on their phone, one on their laptop). Each enrollment creates a separate credential linked to the same user.

Token Expiry

Enrollment tokens are single-use and expire after the configured TTL (default: 1 hour). Generate a new token each time a user initiates enrollment.

Popup Blocked?

Ensure enrollPasskey() is called in response to a user gesture (e.g., button click). Browsers block popups that are not triggered by user interaction.