On this page
  1. Install
  2. Compose the service
  3. Configuration reference
  4. Passkey bridge
  5. Other bridge contracts
  6. Security behavior
  7. Persistence and testing
  8. Boundary
  9. API entry points and requirements
  10. Peer dependencies

@playstack/mfa

Passkey-first MFA, TOTP, recovery codes, recent-auth proofs, and trusted-device decisions.

Free. MIT licensed. Check preview availability before installing. See package access.

@playstack/mfa provides passkey-first step-up authentication, TOTP, recovery codes, recent-auth proofs, trusted-device decisions, and account policy without taking session ownership from @playstack/auth.

Install

sh
npm install @playstack/mfa @playstack/core @playstack/crypto @playstack/devices @playstack/events

Install @simplewebauthn/server only when using the optional Node adapter.

Compose the service

ts
import { createMfa } from '@playstack/mfa'
import { simpleWebAuthnPasskeys } from '@playstack/mfa/webauthn'

export const mfa = createMfa({
  persistence,
  crypto: applicationCrypto,
  webCrypto: globalThis.crypto,
  recoveryHasher: passwordGradeRecoveryHasher,
  passkeys: simpleWebAuthnPasskeys(),
  limiter: mfaAttemptLimiter,
  events,
  clock,
  ids,
  issuer: 'Example App',
  rpId: 'app.example.com',
  rpName: 'Example App',
  origins: ['https://app.example.com'],
  trustedDevices: devices,
})

Configuration reference

MfaOptions propertyRequiredPurpose
persistenceYesTransactional credentials, challenges, recovery sets, and replay locks.
cryptoYesEncryption plus purpose-bound recent-auth signing and verification.
webCryptoYesTOTP HMAC and secure random bytes.
recoveryHasherYesPassword-grade recovery-code hash and verify bridge.
passkeysYesWebAuthn options and ceremony verification bridge.
limiterYesFail-closed attempt limiter by method and user.
events, clock, idsYesTyped security events and deterministic primitives.
issuerYesTOTP issuer, maximum 200 characters.
rpId, rpNameYesWebAuthn relying-party ID and display name.
originsYesOne or more exact HTTPS WebAuthn origins.
trustedDevicesNoDevice trust lookup and grant bridge.
challengeTtlMsNoPositive WebAuthn challenge lifetime; defaults to five minutes.
recentAuthTtlNoSigned proof lifetime; defaults to 5m.
recoveryCodeCountNoCodes per set; defaults to 10 and cannot exceed 50.
maxTrustedDeviceTtlMsNoTrust-grant ceiling; defaults to 30 days.

Passkey bridge

PasskeyAdapter builds registration/authentication options and verifies both ceremonies against the service-supplied challenge, exact origins, RP ID, credential public key, and sign count. The service owns challenge lifetime and single use, credential uniqueness, discovery, and persisted sign counts.

The included simpleWebAuthnPasskeys adapter defaults user verification to required, prefers discoverable credentials, requests no attestation, hashes internal user IDs into fixed-size handles, and omits the allowlist for discoverable sign-in. Use userVerification: 'preferred' only if another factor provides verification.

Other bridge contracts

ContractKey members
MfaPersistenceTransactional credentials, single-use challenges, recovery sets, and locked recovery-code consumption.
MfaCryptoRandom tokens, encryption, and purpose-bound sign/verify; compatible with @playstack/crypto.
RecoveryCodeHasherhash(code) and verify(hash, code) using a password-grade algorithm.
MfaAttemptLimiterconsume(method, userId) returning allowed and optional retryAt.
TrustedDeviceManagerisTrusted and trust; implemented structurally by @playstack/devices.

Security behavior

  • TOTP uses HMAC-SHA1, a 30-second period, six digits, a one-step window, encrypted secrets, and counter replay prevention.
  • Recovery codes are displayed once, activated only after acknowledgement, consumed atomically, and retained after use.
  • Regenerating codes does not invalidate the previous set until the replacement is acknowledged.
  • Sign-count regressions are persisted for detection but do not hard-lock synced passkeys.

MfaService implements auth’s StepUpVerifier. Register auth’s MFA-change handler for both enrollment and disable events so credential changes revoke existing sessions atomically. Route mfa.verification.locked to security notifications as a transactional event that bypasses preferences.

Persistence and testing

@playstack/mfa/prisma provides locked PostgreSQL persistence. Its managed, security-critical fragment is non-ejectable and declares its reverse User relations as model extensions. playstack database sync composes those fields into the selected managed auth artifact and validates the complete Prisma relation graph before writing. If an application owns the User model, it must supply the extension target explicitly. Applications still own migrations. @playstack/mfa/testing provides in-memory persistence and deterministic bridge fakes.

Boundary

MFA does not identify devices, issue sessions, choose account policy, or send lockout notifications. The Workers-safe core accepts any passkey adapter; Node-only WebAuthn support remains an optional subpath.

API entry points and requirements

Reference snapshot: @playstack/mfa@0.1.0-beta.1. Import only the entry point your runtime needs. Paths below are relative to the installed package; use Go to Definition in your editor to inspect exact parameters, return types and overloads. Do not import the declaration-file paths directly.

Public entry pointDeclaration file
@playstack/mfa./dist/index.d.ts
@playstack/mfa/errors./dist/errors.d.ts
@playstack/mfa/prisma./dist/prisma.d.ts
@playstack/mfa/testing./dist/testing.d.ts
@playstack/mfa/webauthn./dist/webauthn.node.d.ts
@playstack/mfa/playstack.artifacts.jsonNo TypeScript declaration (asset or metadata export).
@playstack/mfa/package.jsonNo TypeScript declaration (asset or metadata export).

Node.js engine requirement: >=20. This is not a claim that every entry point works in browsers or Workers.

Peer dependencies

Keep existing framework versions that satisfy these ranges. Install optional peers only when using the corresponding adapter. The package manager resolves ordinary dependencies separately.

PeerCompatible rangeWhen needed
@playstack/crypto0.1.0-beta.1Required by the package.
@playstack/devices0.1.0-beta.1Optional; only for the entry points that use it.
@simplewebauthn/server^13.3.2Optional; only for the entry points that use it.

For a complete first program, start with Getting started. For API lookup and partial-example conventions, see Reading the reference. Provider failures, lifecycle requirements and application responsibilities remain described in the guide above; types alone do not establish production safety.

Go

Playstack Pro tag
OriginsPricingBlogNewsletterChangelogStatusRoadmap
ContributorsCommunityIn Use ShowcaseCase StudiesPartnersSponsors
FAQsSupportContact

© 2026 Playstack. All rights reserved.

With OSS
Terms of ServicePrivacy PolicyCookie PolicyImprint

By

Commune Software