Authsome

Passkey Plugin

FIDO2/WebAuthn passkey registration and authentication with resident keys and platform authenticators.

The passkey plugin implements FIDO2/WebAuthn authentication, allowing users to register and authenticate with biometrics, security keys, or platform authenticators. It wraps the go-webauthn/webauthn library and manages credential storage, registration ceremonies, and authentication ceremonies.

Setup

import (
    "github.com/xraph/authsome"
    "github.com/xraph/authsome/plugins/passkey"
)

eng, err := authsome.NewEngine(
    authsome.WithStore(store),
    authsome.WithPlugin(passkey.New(passkey.Config{
        RPDisplayName:  "My App",
        RPID:           "example.com",
        RPOrigins:      []string{"https://example.com"},
        SessionTimeout: 5 * time.Minute,
    })),
)

Configuration

OptionTypeDefaultDescription
RPDisplayNamestring"AuthSome"Relying party display name shown during WebAuthn ceremonies
RPIDstring"localhost"Relying party identifier, typically the domain name
RPOrigins[]string[]Allowed origins for WebAuthn ceremonies
SessionTimeouttime.Duration5mHow long a WebAuthn ceremony session remains valid

Implemented interfaces

InterfacePurpose
PluginBase plugin identity ("passkey")
OnInitInitializes the WebAuthn library and captures bridges
RouteProviderRegisters registration and authentication endpoints
MigrationProviderContributes the passkey_credentials table
AuthMethodContributorReports registered passkeys as linked auth methods

Registration ceremony

The registration ceremony creates a new passkey credential for the authenticated user.

Step 1: Begin registration

POST /v1/auth/passkey/register/begin

The server generates a challenge and returns PublicKeyCredentialCreationOptions for the browser's navigator.credentials.create() API.

{
  "publicKey": {
    "rp": {"name": "My App", "id": "example.com"},
    "user": {"id": "base64...", "name": "alice", "displayName": "Alice"},
    "challenge": "base64...",
    "pubKeyCredParams": [
      {"type": "public-key", "alg": -7},
      {"type": "public-key", "alg": -257}
    ],
    "authenticatorSelection": {
      "residentKey": "preferred",
      "userVerification": "preferred"
    }
  }
}

Step 2: Complete registration

POST /v1/auth/passkey/register/finish

The client sends the AuthenticatorAttestationResponse from the browser. The server validates the attestation, extracts the public key, and stores the credential.

{
  "id": "base64-credential-id",
  "rawId": "base64-raw-id",
  "response": {
    "clientDataJSON": "base64...",
    "attestationObject": "base64..."
  },
  "type": "public-key"
}

Authentication ceremony

The authentication ceremony verifies the user's passkey credential.

Step 1: Begin authentication

POST /v1/auth/passkey/login/begin

Returns PublicKeyCredentialRequestOptions for navigator.credentials.get().

Step 2: Complete authentication

POST /v1/auth/passkey/login/finish

The client sends the AuthenticatorAssertionResponse. The server verifies the signature against the stored public key, updates the sign count, and creates a session.

Credential types

Resident keys (discoverable credentials)

When residentKey is set to "required" or "preferred", the authenticator stores the credential internally. Users can authenticate without entering a username first -- the authenticator presents all stored credentials for the relying party.

Non-resident keys

The server must provide a list of allowed credential IDs during authentication. The user must first identify themselves (e.g., by entering an email) so the server can look up their credentials.

Platform vs roaming authenticators

  • Platform authenticators -- Built into the device (Touch ID, Face ID, Windows Hello). Use authenticatorAttachment: "platform" to prefer these.
  • Roaming authenticators -- External security keys (YubiKey, SoloKeys). Use authenticatorAttachment: "cross-platform".

Credential storage

Each registered credential stores:

FieldDescription
CredentialIDUnique identifier for the credential
PublicKeyThe credential's public key (used for signature verification)
AttestationTypeAttestation type from the registration response
TransportSupported transports (usb, nfc, ble, internal)
SignCountMonotonically increasing counter for clone detection
AAGUIDAuthenticator Attestation GUID
DisplayNameUser-provided label for the credential

Auth method reporting

The passkey plugin implements AuthMethodContributor, returning one entry per registered credential:

{
  "type": "passkey",
  "provider": "passkey",
  "label": "MacBook Pro Touch ID",
  "linked_at": "2024-11-01T10:00:00Z"
}

API routes

MethodPathDescription
POST/v1/auth/passkey/register/beginStart passkey registration ceremony
POST/v1/auth/passkey/register/finishComplete passkey registration
POST/v1/auth/passkey/login/beginStart passkey authentication ceremony
POST/v1/auth/passkey/login/finishComplete passkey authentication
GET/v1/auth/passkey/credentialsList user's registered passkeys
DELETE/v1/auth/passkey/credentials/:idRemove a registered passkey

Ceremony state management

WebAuthn ceremonies require server-side state between the begin and finish steps. The passkey plugin uses the engine's ceremony store (defaulting to in-memory) to persist challenge data. For multi-instance deployments, configure a shared ceremony store (e.g., Redis-backed).

On this page