PasskeyBase

JavaScript SDK

The @passkeybase/js package is the core client-side SDK. It handles the OAuth/PKCE flow, token management, and passkey enrollment in any browser environment. All framework SDKs (React, Vue, etc.) are built on top of this package.


Installation

Terminal
npm install @passkeybase/js

Quick Start

Initialize the SDK with your client ID and tenant domain, then trigger a login.

app.ts
import { PasskeyBase } from '@passkeybase/js';

const pb = new PasskeyBase({
  clientId: 'pk_live_abc123',
  domain: 'myapp.auth.ing',
  redirectUri: window.location.origin + '/callback',
});
Login
// Send the user to the hosted login page
await pb.loginWithRedirect();

After the user authenticates and is redirected back, retrieve their profile:

Check auth state
// After handling the callback, check auth state
const isLoggedIn = await pb.isAuthenticated();

if (isLoggedIn) {
  const user = await pb.getUser();
  console.log('Hello,', user.displayName);
}

Authentication

loginWithRedirect()

Redirects the user to the PasskeyBase hosted login page. After authentication, they are redirected back to your redirectUri with an authorization code.

loginWithRedirect()
// Basic redirect
await pb.loginWithRedirect();

// With options
await pb.loginWithRedirect({
  redirectUri: '/auth/callback',
  scopes: ['openid', 'profile', 'email'],
  state: 'return=/settings',
});

handleRedirectCallback()

Call this on your callback page. It extracts the authorization code from the URL, exchanges it for tokens via PKCE, and caches the result.

handleRedirectCallback()
// On your callback page (e.g., /callback)
const result = await pb.handleRedirectCallback();

// result contains:
// {
//   accessToken: string;
//   idToken: string;
//   expiresIn: number;
//   tokenType: 'Bearer';
//   state?: string;
// }

// Redirect the user into the app
window.location.href = '/dashboard';

getAccessToken()

Returns the current access token. If the token has expired and refresh tokens are enabled, a new token is fetched automatically.

getAccessToken()
// Get the current access token (refreshes automatically if expired)
const token = await pb.getAccessToken();

// Use the token to call your API
const response = await fetch('https://api.myapp.com/data', {
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

isAuthenticated()

Returns true if the user has a valid, non-expired session.

isAuthenticated()
const loggedIn = await pb.isAuthenticated();

if (loggedIn) {
  showDashboard();
} else {
  showLandingPage();
}

logout()

Clears the local session and redirects to the PasskeyBase logout endpoint to end the server-side session.

logout()
// Log out and redirect to the home page
await pb.logout();

// With a custom post-logout redirect
await pb.logout({
  returnTo: window.location.origin,
});

Passkey Enrollment

enrollPasskey()

Opens a popup window where an already-authenticated user can register a new passkey and bind it to their account. Your backend must generate an enrollment token via the Management API first.

enrollPasskey()
// 1. Fetch an enrollment token from your backend
const res = await fetch('/api/enrollment-token', {
  method: 'POST',
  headers: { Authorization: `Bearer ${accessToken}` },
});
const { token } = await res.json();

// 2. Open the enrollment popup
await pb.enrollPasskey(token);

// The user creates a passkey in the popup, then control returns here.
console.log('Passkey enrolled successfully');

handleEnrollmentCallback()

If you use redirect-based enrollment instead of the default popup flow, call this on the enrollment callback page to finalize the process.

handleEnrollmentCallback()
// If using redirect-based enrollment instead of a popup
const enrollResult = await pb.handleEnrollmentCallback();

// enrollResult: {
//   credentialId: string;
//   externalId: string;
//   status: 'enrolled';
// }

Configuration Options

The full set of options you can pass to the PasskeyBase constructor:

Configuration
const pb = new PasskeyBase({
  // Required
  clientId: 'pk_live_abc123',
  domain: 'myapp.auth.ing',

  // Optional
  redirectUri: '/callback',              // Default redirect URI after login
  scopes: ['openid', 'profile'],         // OAuth scopes (default: ['openid'])
  audience: 'https://api.myapp.com',     // API audience for access tokens
  cacheLocation: 'localstorage',         // 'memory' | 'localstorage' (default: 'memory')
  useRefreshTokens: true,                // Use refresh tokens (default: false)
  leeway: 60,                            // Clock skew tolerance in seconds (default: 60)
});
OptionTypeDefaultDescription
clientIdstring--Your OAuth client ID from the dashboard.
domainstring--Your tenant domain (e.g., myapp.auth.ing).
redirectUristring--Default redirect URI after authentication.
scopesstring[]['openid']OAuth scopes to request.
audiencestring--API audience identifier for access tokens.
cacheLocationstring'memory'Where to store tokens: 'memory' or 'localstorage'.
useRefreshTokensbooleanfalseEnable refresh token rotation for silent re-auth.
leewaynumber60Clock skew tolerance in seconds for token validation.

TypeScript Types

The SDK ships with full TypeScript definitions. All interfaces and types are exported from the package root.

types.ts
import type {
  PasskeyBaseOptions,
  LoginWithRedirectOptions,
  AuthResult,
  User,
  EnrollPasskeyOptions,
  LogoutOptions,
} from '@passkeybase/js';

// PasskeyBaseOptions — constructor config
interface PasskeyBaseOptions {
  clientId: string;
  domain: string;
  redirectUri?: string;
  scopes?: string[];
  audience?: string;
  cacheLocation?: 'memory' | 'localstorage';
  useRefreshTokens?: boolean;
  leeway?: number;
}

// User — authenticated user profile
interface User {
  sub: string;
  displayName?: string;
  email?: string;
  emailVerified?: boolean;
  credentials: Credential[];
}

// AuthResult — returned from handleRedirectCallback
interface AuthResult {
  accessToken: string;
  idToken: string;
  expiresIn: number;
  tokenType: 'Bearer';
  state?: string;
}

Error Handling

All SDK methods throw a PasskeyBaseError on failure. Each error includes a code property you can use for programmatic error handling.

Error handling
import { PasskeyBaseError, ErrorCode } from '@passkeybase/js';

try {
  await pb.loginWithRedirect();
} catch (err) {
  if (err instanceof PasskeyBaseError) {
    switch (err.code) {
      case ErrorCode.POPUP_CLOSED:
        console.log('User closed the popup');
        break;
      case ErrorCode.TOKEN_EXPIRED:
        console.log('Session expired — redirecting to login');
        await pb.loginWithRedirect();
        break;
      case ErrorCode.NETWORK_ERROR:
        console.log('Network issue — please try again');
        break;
      default:
        console.error('Auth error:', err.message);
    }
  }
}
Error CodeDescription
POPUP_CLOSEDThe user closed the enrollment popup before completing.
TOKEN_EXPIREDThe access or enrollment token has expired.
NETWORK_ERRORA network request failed (DNS, timeout, etc.).
INVALID_STATEThe OAuth state parameter did not match (possible CSRF).
MISSING_CONFIGA required configuration option was not provided.

Next steps