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
npm install @passkeybase/jsQuick Start
Initialize the SDK with your client ID and tenant domain, then trigger a login.
import { PasskeyBase } from '@passkeybase/js';
const pb = new PasskeyBase({
clientId: 'pk_live_abc123',
domain: 'myapp.auth.ing',
redirectUri: window.location.origin + '/callback',
});// Send the user to the hosted login page
await pb.loginWithRedirect();After the user authenticates and is redirected back, retrieve their profile:
// 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.
// 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.
// 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.
// 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.
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.
// 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.
// 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.
// 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:
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)
});| Option | Type | Default | Description |
|---|---|---|---|
clientId | string | -- | Your OAuth client ID from the dashboard. |
domain | string | -- | Your tenant domain (e.g., myapp.auth.ing). |
redirectUri | string | -- | Default redirect URI after authentication. |
scopes | string[] | ['openid'] | OAuth scopes to request. |
audience | string | -- | API audience identifier for access tokens. |
cacheLocation | string | 'memory' | Where to store tokens: 'memory' or 'localstorage'. |
useRefreshTokens | boolean | false | Enable refresh token rotation for silent re-auth. |
leeway | number | 60 | Clock 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.
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.
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 Code | Description |
|---|---|
POPUP_CLOSED | The user closed the enrollment popup before completing. |
TOKEN_EXPIRED | The access or enrollment token has expired. |
NETWORK_ERROR | A network request failed (DNS, timeout, etc.). |
INVALID_STATE | The OAuth state parameter did not match (possible CSRF). |
MISSING_CONFIG | A required configuration option was not provided. |
Next steps
- React SDK -- hooks and components for React apps
- Vue SDK -- composables and plugin for Vue 3
- Next.js SDK -- server and client auth for Next.js
- Node.js SDK -- server-side Management API client