npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@olton/passkey

v0.2.1

Published

Passkey SDK for web authentication and payment step-up scenarios

Readme

@olton/passkey

Українська версія: readme.md

Passkey SDK is a web authentication library that enables passkey-based flows such as passwordless login, sensitive action confirmation, and payment step-up.

Table of Contents

Platform Authenticators

  • On Windows, this library can be used with Windows Hello as a platform authenticator.
  • On macOS and iOS, it can be used with Touch ID or Face ID as a platform authenticator.
  • On Android, it can be used with built-in biometric authentication as a platform authenticator.
  • On Linux, platform authenticator availability varies significantly, so the library is designed to work primarily with roaming authenticators (security keys) and phone passkey flow.

Cross-platform capability matrix: docs/platform-matrix.md.

Platform runbooks:

Documentation Index

Payment Integration Guides

Payment Flow Diagrams

Account service flow

sequenceDiagram
	participant U as User
	participant F as Frontend
	participant S as Passkey SDK
	participant B as Backend

	U->>F: Click "Pay"
	F->>S: confirmPayment(input with accountId)
	S->>B: beginPaymentStepUp(input)

	alt Account has enrolled passkey
		B-->>S: assertion options
		S-->>F: request WebAuthn assertion
		F->>U: Prompt biometrics (FaceID/TouchID)
		U-->>F: Confirm biometrics
		F->>S: WebAuthn assertion
		S->>B: finishPaymentStepUp(assertion)
		B-->>S: decision = approved
		S-->>F: PaymentStepUpResult(approved)
		F->>U: Payment success
	else Account not enrolled
		B-->>S: decision = enrollment_required
		S-->>F: PaymentStepUpResult(enrollment_required)

		alt Mandatory enrollment policy
			F->>U: Start verification/enrollment flow
			F->>F: OTP/verification -> passkey enrollment
			F->>S: confirmPayment(retry)
			S->>B: beginPaymentStepUp(retry)
			B-->>S: decision = approved or fallback_to_3ds
			S-->>F: Retry result
		else Optional enrollment policy
			F->>F: Run allowed first-payment fallback
			F->>U: Offer passkey enrollment after success
		end
	end

	alt Auth failed or timeout
		B-->>S: rejected/timeout or mapped failure
		S-->>F: non-approved result
		F->>U: Show failure/retry UI
	end

Card service flow

sequenceDiagram
	participant U as User
	participant F as Frontend
	participant B as Backend
	participant P as Payment Gateway

	U->>F: Enter card details
	Note over F: encrypt(cardData) <br/>(src/crypto/index.ts)
	F->>B: Send encrypted bundle

	B->>B: decrypt(bundle) -> PAN
	B->>B: Check if passkey exists for this card/token

	alt Passkey exists
		B-->>F: Request step-up (WebAuthn)
		F->>U: Biometrics (FaceID/TouchID)
		U-->>F: Confirmation
		F->>B: WebAuthn assertion
	else No passkey / 3DS required
		B-->>F: Redirect to 3DS
		U->>F: OTP / app approval
		F->>B: 3DS result
	end

	alt Authentication completed
		B->>P: Authorize payment (PAN/Token)
		P-->>B: Payment status (success/declined/declined_fraud/error)

		alt Payment success
			alt Passkey not enrolled yet
				B-->>F: Offer passkey enrollment
				F->>U: "Use FaceID for future purchases?"
				alt User accepts
					U->>F: Yes
					F->>B: Passkey registration (WebAuthn attestation)
					B-->>F: Passkey linked (User + Card/Token + Passkey)
				else User declines
					U->>F: No
					Note over F,B: Next payments for this card/token follow <br/>current flow: 3DS or step-up
				end
			else Passkey already enrolled
				Note over B: Faster future checkouts with step-up
			end

			B-->>F: Final status (success)
			F->>U: Purchase complete
		else Payment failed (declined / declined_fraud / error)
			B-->>F: Payment error (code/reason)
			F->>U: Payment failed, try another method
		end
	else Authentication failed / timeout
		B-->>F: Authentication error (failed/timeout)
		F->>U: Payment failed, authentication was not completed
	end

Sensitive Vault Flow Diagram

sequenceDiagram
	participant U as User
	participant F as Sensitive Demo UI
	participant S as Passkey SDK
	participant B as Backend
	participant V as Sensitive Vault

	Note over U,F: One-time setup
	U->>F: Click "Register Passkey"
	F->>S: register(user)
	S->>B: /passkeys/registration/options
	B-->>S: Creation options
	S-->>F: navigator.credentials.create
	F->>U: Biometric verification
	F->>S: Attestation result
	S->>B: /passkeys/registration/verify
	B-->>F: Registration verified

	Note over U,F: Hide secret flow
	U->>F: Enter secret + click "Hide Secret"
	F->>S: login(username)
	S->>B: /passkeys/authentication/options
	B-->>S: Assertion options
	S-->>F: navigator.credentials.get
	F->>U: Biometric verification
	F->>S: Assertion result
	S->>B: /passkeys/authentication/verify
	B-->>F: session.accessToken
	F->>F: Encrypt secret (AES-GCM)
	F->>B: POST /demo/sensitive/store (encrypted payload + token)
	B->>V: Store encrypted payload
	B-->>F: Stored

	Note over U,F: Reveal secret flow
	U->>F: Click "Unlock Secret"
	F->>S: login(username)
	S->>B: /passkeys/authentication/options + verify
	B-->>F: session.accessToken
	F->>B: POST /demo/sensitive/reveal (token)
	B->>V: Load encrypted payload
	V-->>B: encryptedData + iv + keyMaterial
	B-->>F: Encrypted payload
	F->>F: Decrypt locally (AES-GCM)
	F->>U: Show decrypted secret

	Note over U,F: Clear secret flow
	U->>F: Click "Clear Secret"
	F->>S: login(username)
	S->>B: /passkeys/authentication/options + verify
	B-->>F: session.accessToken
	F->>B: POST /demo/sensitive/clear (token)
	B->>V: Delete payload
	B-->>F: Cleared

Key Benefits

This library helps implement passkey-based WebAuthn flows for:

  • passwordless login
  • sensitive action confirmation
  • payment step-up as an alternative to 3DS (with fallback)
  • scenario-oriented orchestration for web clients

Features

  • typed WebAuthn DTOs for backend contracts
  • browser WebAuthn transport service
  • pluggable backend adapter
  • high-level authentication and payment services
  • unified facade client for integration
  • generated TypeScript declaration files

Installation

npm i @olton/passkey

Quick Start

import { createBackendAdapter, createPasskeyClient } from '@olton/passkey';

const adapter = createBackendAdapter({
  baseUrl: 'https://api.example.com',
});

const passkey = createPasskeyClient({ adapter });

await passkey.register({
  user: {
    id: 'user_1',
    username: '[email protected]',
    displayName: 'Demo User',
  },
});

const loginResult = await passkey.login({
  username: '[email protected]',
});

Client-to-Backend Integration (Without Demo Server)

The SDK includes only client-side orchestration. You need to provide your own backend API that returns WebAuthn options and verifies WebAuthn results.

Demo servers in this repository are reference implementations, not required runtime dependencies.

SDK Methods -> Backend Calls

  1. passkey.register(input):
  • POST /passkeys/registration/options
  • POST /passkeys/registration/verify
  1. passkey.login(input) and passkey.confirmSensitiveAction(input):
  • POST /passkeys/authentication/options
  • POST /passkeys/authentication/verify
  1. passkey.confirmPayment(input):
  • POST /passkeys/payments/options
  • POST /passkeys/payments/verify

Minimal Setup Checklist

  1. Implement the 6 endpoints listed above on your backend.
  2. Ensure every challenge is one-time and short-lived.
  3. Validate origin, RP ID, signature, and counter on the server.
  4. Point the SDK adapter to your API URL.
import { createBackendAdapter, createPasskeyClient } from '@olton/passkey';

const adapter = createBackendAdapter({
  baseUrl: 'https://api.your-domain.com',
});

const passkey = createPasskeyClient({ adapter });

If your routes differ, explicitly override endpoint paths:

const adapter = createBackendAdapter({
  baseUrl: 'https://api.your-domain.com',
  endpoints: {
    beginRegistration: '/v1/passkeys/register/options',
    finishRegistration: '/v1/passkeys/register/verify',
  },
});

All routes:

export const DEFAULT_PASSKEY_BACKEND_ENDPOINTS: Readonly<PasskeyBackendEndpoints> = {
  beginRegistration: '/passkeys/registration/options',
  finishRegistration: '/passkeys/registration/verify',
  beginAuthentication: '/passkeys/authentication/options',
  finishAuthentication: '/passkeys/authentication/verify',
  beginPaymentStepUp: '/passkeys/payments/options',
  finishPaymentStepUp: '/passkeys/payments/verify',
};

See full request/response schema in docs/api-contract.md.

Module Exports

Below is the complete list of exports from @olton/passkey.

Client Facade

Module docs: src/core/readme.md

  • createPasskeyClient - factory for creating a PasskeyClient.
  • PasskeyClient - main SDK facade for registration, login, step-up, and scenario flows.
  • PasskeyClientConfig - facade configuration (backend adapter and optional WebAuthn service).

Backend Adapter

Module docs: src/adapters/readme.md

  • PasskeyBackendAdapter - API adapter contract for registration/auth/payment flows.
  • PasskeyBackendEndpoints - endpoint path set for the fetch adapter.
  • DEFAULT_PASSKEY_BACKEND_ENDPOINTS - default endpoint map used by createBackendAdapter.
  • FetchBackendAdapterConfig - fetch adapter config (base URL, headers, endpoints).
  • createBackendAdapter - creates an adapter to integrate with your backend via fetch.

Authentication and Payment Services

Module docs:

Use Case Contracts

Module docs: src/use-cases/readme.md

  • LoginUseCaseRequest - payload for login scenario.
  • PaymentStepUpUseCaseRequest - payload for payment step-up scenario.
  • SensitiveActionUseCaseRequest - payload for sensitive action confirmation scenario.
  • PasswordlessRecoveryUseCaseRequest - payload for passwordless recovery scenario.
  • WebClientUseCaseRequest - union of all supported scenario request types.
  • WebClientUseCaseResponse - unified response type for orchestration scenarios.

WebAuthn Transport

Module docs: src/webauthn/readme.md

  • WebAuthnService - browser WebAuthn transport service (credential creation + assertion).

SDK Errors

Module docs: src/errors/readme.md

  • PasskeyError - base SDK error.
  • PasskeyNotSupportedError - browser/runtime does not support WebAuthn.
  • UserCancelledError - user cancelled the passkey ceremony.
  • BackendAdapterError - HTTP/contract errors when interacting with the backend adapter.

Base64url Utilities

Module docs: src/utils/readme.md

  • base64UrlToArrayBuffer - converts base64url to ArrayBuffer.
  • arrayBufferToBase64Url - converts ArrayBuffer to base64url.
  • uint8ArrayToBase64Url - converts Uint8Array to base64url.
  • base64UrlToUint8Array - converts base64url to Uint8Array.

Generic Crypto Utilities

Module docs: src/crypto/readme.md

  • encrypt - generic AES-GCM encryption for JSON-serialized payloads.
  • decrypt - generic AES-GCM decryption for serialized payload bundles.
  • EncryptedPayloadBundle - shape of serialized encrypted payload bundle.

Core Domain Types and Decisions

Module docs: src/types/readme.md

  • Base64Url - string in base64url format.
  • StepUpDecision - payment step-up decision (approved, fallback_to_3ds, rejected, enrollment_required).
  • WebClientScenario - supported web client business scenarios.

User Profile, Risk Signals, and Payment Context

Module docs: src/types/readme.md

  • PasskeyUser - user data for passkey registration.
  • RiskSignals - optional signals for fraud/risk analysis.
  • PaymentContext - business context for payment confirmation.
  • CardPaymentContext - deprecated alias for backward compatibility.

WebAuthn JSON DTOs

Module docs: src/types/readme.md

  • PublicKeyCredentialDescriptorJSON - JSON representation of credential descriptor.
  • PublicKeyCredentialUserEntityJSON - JSON representation of WebAuthn user entity.
  • PublicKeyCredentialCreationOptionsJSON - JSON credential creation options (registration).
  • PublicKeyCredentialRequestOptionsJSON - JSON assertion options (authentication/payment).
  • CredentialAttestationJSON - serialized passkey registration result.
  • CredentialAssertionJSON - serialized passkey authentication result.

Backend Request Types

Module docs: src/types/readme.md

  • BeginRegistrationInput - payload to request registration options.
  • FinishRegistrationInput - payload to verify registration.
  • BeginAuthenticationInput - payload to request authentication options.
  • FinishAuthenticationInput - payload to verify authentication.
  • BeginPaymentStepUpInput - payload to request payment step-up options.
  • FinishPaymentStepUpInput - payload to verify payment step-up.

Verification Results and Session

Module docs: src/types/readme.md

  • AuthSession - session data after successful authentication.
  • RegistrationVerificationResult - registration verification result.
  • AuthenticationVerificationResult - authentication verification result.
  • PaymentStepUpVerificationResult - backend payment step-up verification result.
  • PaymentStepUpResult - final client step-up result (including fallback/3DS flags).

Usage Examples

This section is written for beginners: follow the steps in order.

What Happens in Practice

  1. Initialize the SDK client.
  2. Register a passkey once per user/device.
  3. Later, call login/confirm/payment methods when needed.

Step 1) Create the Client (Once)

Do this during app startup (for example, when your page/app initializes).

import { createBackendAdapter, createPasskeyClient } from '@olton/passkey';

const adapter = createBackendAdapter({
  baseUrl: 'http://localhost:4100', // replace with your backend URL
});

const passkey = createPasskeyClient({ adapter });

Step 2) Register a Passkey (First Time Only)

Call this when the user clicks a button like "Enable passkey".

const registration = await passkey.register({
  user: {
    id: 'user_1',
    username: '[email protected]',
    displayName: 'Demo User',
  },
});

if (registration.verified) {
  console.log('Passkey registration successful');
}

Expected result:

  1. Browser opens the passkey prompt.
  2. User confirms with Windows Hello / Face ID / Touch ID.
  3. The backend verifies and stores the credential.

Step 3) Use Passkey Flows

After successful registration, use any of these methods.

A) Passwordless Login

const loginResult = await passkey.login({
  username: '[email protected]',
  context: {
    source: 'web',
  },
});

if (loginResult.verified) {
  console.log('Login successful');
}

B) Sensitive Action Confirmation

const confirmResult = await passkey.confirmSensitiveAction({
  userId: 'user_1',
  context: {
    action: 'change-payout-account',
  },
});

if (confirmResult.verified) {
  console.log('Sensitive action confirmed');
}

C) Payment Step-Up

const paymentResult = await passkey.confirmPayment({
  payment: {
    paymentIntentId: 'pi_100',
    amountMinor: 45000,
    currency: 'UAH',
    merchantId: 'merchant_1',
    accountId: 'click2pay_account_1',
  },
  userId: 'user_1',
});

if (paymentResult.decision === 'fallback_to_3ds') {
  // your fallback path when passkey cannot approve payment
}

if (paymentResult.decision === 'enrollment_required') {
  // run account verification (email/phone OTP) and passkey enrollment flow
}

Passkey enrollment for this flow should happen once per account (for example, after OTP verification), then the same passkey is reused for all cards in that account.

D) Single Entry Point (Scenario Mode)

Use this if you prefer one unified method instead of many separate methods.

const result = await passkey.runUseCase({
  scenario: 'payment-step-up',
  input: {
    payment: {
      paymentIntentId: 'pi_101',
      amountMinor: 1000,
      currency: 'UAH',
      merchantId: 'merchant_1',
    },
    userId: 'user_1',
  },
});

console.log('Use case result:', result);

Common Beginner Mistakes

  1. Calling login() before register() for a new user.
  2. Using the wrong baseUrl (frontend points to an API that is not running).
  3. Testing on an unsupported origin (use localhost or HTTPS).
  4. Forgetting backend verification endpoints.

Run Demo Locally

1) Start the Demo Backend (Windows Hello)

npm run server

Default URL: http://localhost:4100

This server returns WebAuthn policies for platform authenticators (authenticatorAttachment: "platform") and userVerification: "required".

2) Start Demo UI

npm run ui

Open: http://localhost:5173

Dedicated login/password -> passkey onboarding demo: http://localhost:5173/login/index.html

Dedicated sensitive data vault demo with passkey access: http://localhost:5173/sensitive/index.html

3) Try Demo Scenarios

  • Register passkey
  • Login with passkey
  • Confirm a sensitive action
  • Confirm a payment with account-level passkey reuse

Set API Base URL to your reachable backend URL (for local machine tests, typically http://localhost:4100).

For complete local demo steps and troubleshooting, see docs/demo-runbook.md.

Dedicated setup runbooks:

Build Outputs

  • ESM bundle: dist/prod/passkey.es.js
  • CJS bundle: dist/prod/passkey.cjs.js
  • TypeScript declarations: dist/types/index.d.ts

Scripts

  • npm run ui - start demo UI (Vite dev server)
  • npm run server - start TypeScript demo backend
  • npm run start - start backend and demo UI together
  • npm run build:dev - build development bundle
  • npm run build:types - generate TypeScript declarations
  • npm run build:prod - build production bundles and declarations
  • npm run build - lint + typecheck + test + production build
  • npm run preview - run preview for production build
  • npm run typecheck - run TypeScript type checker
  • npm run lint - run linter
  • npm run test - run test suite
  • npm run test:watch - run tests in watch mode
  • npm run pub - run build and publish package to npm

Contributing

Contributions are welcome. Please open issues for bugs or feature requests, and submit pull requests for improvements.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Support

If you like this project, please consider supporting it:


Copyright (c) 2026 by Serhii Pimenov. All Rights Reserved.