Skip to content

PasskeyAuth

Viames Marino edited this page Feb 24, 2026 · 1 revision

Pair framework: PasskeyAuth

Pair\Services\PasskeyAuth implements Passkey/WebAuthn registration and authentication flows.

It manages challenge lifecycle, verifies WebAuthn payloads, persists credentials, and finalizes login.

Constructor

new \Pair\Services\PasskeyAuth(
    ?string $rpId = null,
    ?string $rpName = null,
    ?array $allowedOrigins = null,
    int $challengeTtl = 300
);

Resolution order:

  • rpId: constructor arg -> PASSKEY_RP_ID -> host from BASE_HREF/HTTP_HOST
  • rpName: constructor arg -> PASSKEY_RP_NAME -> APP_NAME -> "Pair App"
  • allowedOrigins: constructor arg -> PASSKEY_ALLOWED_ORIGINS -> BASE_HREF

If RP ID or allowed origins are missing, it throws PairException(MISSING_CONFIGURATION).

Main methods

beginAuthentication(?User $user = null, array $allowCredentialIds = [], array $options = []): array

Creates publicKey options for navigator.credentials.get(...).

If $user is passed and no allow-list is provided, active user passkeys are loaded automatically.

beginRegistration(User $user, ?string $userDisplayName = null, array $excludeCredentialIds = [], array $options = []): array

Creates publicKey options for navigator.credentials.create(...).

By default excludes already active credentials of the same user.

completeAuthentication(array $credential, string $timezone, ?User $user = null): \stdClass

Consumes challenge, validates assertion (type, challenge, origin, RP ID hash, signature, counter), then returns the output of User::doLoginById(...).

On failure it returns a standard failed-login object (error=true, message, userId=null, sessionId=null) and logs failed attempts via Audit::loginFailed(...).

registerCredential(User $user, array $credential, ?string $label = null): UserPasskey

Consumes registration challenge, validates payload, extracts/stores public key and metadata, and persists a UserPasskey.

Security details

  • Challenges are session-based (SESSION_KEY = "__pair_passkey_challenges") and single-use.
  • Challenge expiration defaults to 300 seconds.
  • Client data origin must match configured allowed origins.
  • Signature verification requires OpenSSL (openssl_verify / openssl_pkey_get_public).
  • Counter rollback is rejected during authentication.
  • Optional user verification enforcement is driven by PASSKEY_REQUIRE_USER_VERIFICATION.

Required browser payload fields

Authentication:

  • id or rawId
  • response.clientDataJSON
  • response.authenticatorData
  • response.signature

Registration:

  • id or rawId
  • response.clientDataJSON
  • response.publicKeyPem or response.publicKey (base64url DER SPKI)

Environment variables

  • PASSKEY_RP_ID
  • PASSKEY_RP_NAME
  • PASSKEY_ALLOWED_ORIGINS (comma-separated)
  • PASSKEY_REQUIRE_USER_VERIFICATION

See also: PasskeyController, UserPasskey, User, Session, Audit, PairPasskey.js.

Clone this wiki locally