Skip to content

Latest commit

 

History

History
57 lines (45 loc) · 2.29 KB

File metadata and controls

57 lines (45 loc) · 2.29 KB

0.5 Breaking Migration

Version 0.5 removes the non-atomic passkey-registration fallback from WebAuthnAdapter. Authentication, challenge consumption, credential listing, counter advancement, and deletion remain on the storage adapter. Registration adds a separate persistence capability because only the host application can atomically combine account eligibility, its credential cap, and insertion.

1. Require the registration capability

Any webauthn configuration now requires adapters.webauthn to satisfy WebAuthnRegistrationAdapter:

import type {
  CreateWebAuthnCredentialWithinLimitInput,
  WebAuthnCredentialCreationAdapter,
  WebAuthnCredentialCreationOutcome
} from '@goobits/auth/adapters/webauthn'

class AppWebAuthnAdapter
  extends YourWebAuthnAdapter
  implements WebAuthnCredentialCreationAdapter
{
  async createCredentialWithinLimit(
    input: CreateWebAuthnCredentialWithinLimitInput
  ): Promise<WebAuthnCredentialCreationOutcome> {
    return yourOwnerScopedTransaction(input)
  }
}

Custom adapters that previously inherited the base implementation must add this method. The built-in D1, Drizzle, and PostgreSQL adapters remain valid for storage, authentication, and management, but no longer claim to provide the application-owned registration transaction. MemoryWebAuthnAdapter implements the complete registration contract for one process.

2. Make the mutation genuinely atomic

Inside one transaction or owner-scoped lock:

  1. Verify that the credential owner still exists and may add a sign-in method.
  2. Count the owner's current credentials and return limit-reached at the cap.
  3. Insert by globally unique credential ID without replacing an existing owner.
  4. Return created, duplicate, limit-reached, or owner-unavailable.

Do not implement the method as listCredentials() followed by createCredential(). Concurrent requests can both observe space and exceed the cap. For SQL applications, lock the canonical account/lifecycle row (or use an equivalent serialized transaction) before counting and inserting.

3. Verify consumers

Typecheck every application that enables webauthn. Add a concurrency test against the production database when possible: submit more registrations than the configured cap for one owner and assert that no more than the cap persist.