glasslock/registration

WebAuthn registration ceremony.

Example

import glasslock/registration

// Generate options for the browser
let #(options, challenge) =
  registration.new(
    relying_party: registration.RelyingParty(id: "example.com", name: "My App"),
    user: registration.User(id: user_id, name: "john", display_name: "John"),
    origin: "https://example.com",
  )
  |> registration.build()

// Serialize `options` and send to the browser; receive
// response_json back. Keep `challenge` in memory for a single-node
// deploy; to span processes or nodes, serialize with
// `registration.encode_challenge` and hydrate it back with
// `registration.parse_challenge`.

// Verify the response
case registration.verify_json(response_json:, challenge:) {
  Ok(credential) -> todo as "store credential"
  Error(e) -> todo as "handle error"
}

Types

Supported cryptographic algorithms.

pub type Algorithm {
  Es256
  Ed25519
  Rs256
}

Constructors

  • Es256

    ECDSA with P-256 curve and SHA-256 hash (COSE algorithm -7).

  • Ed25519

    EdDSA with Ed25519 curve (COSE algorithm -8).

  • Rs256

    RSASSA-PKCS1-v1_5 with SHA-256 (COSE algorithm -257).

Authenticator attachment preference.

pub type AuthenticatorAttachment {
  Platform
  CrossPlatform
}

Constructors

  • Platform

    Platform authenticator (e.g., Touch ID, Windows Hello).

  • CrossPlatform

    Roaming authenticator (e.g., USB security key, Bluetooth).

Configuration for a registration request, built up via new and the setter functions, then handed to build to produce browser options and a challenge verifier.

pub opaque type Builder

A finalized registration challenge ready for verification or out-of-process serialization (see encode_challenge and parse_challenge).

pub opaque type Challenge

Errors that can occur during registration verification.

pub type Error {
  VerificationMismatch(field: glasslock.VerificationField)
  UnsupportedKey(reason: String)
  ParseError(message: String)
  InvalidAttestation(reason: String)
  InvalidSignature
  UserPresenceFailed
  UserVerificationFailed
}

Constructors

  • VerificationMismatch(field: glasslock.VerificationField)

    A verification field does not match the expected value.

  • UnsupportedKey(reason: String)

    The key format, algorithm, or curve is not supported.

  • ParseError(message: String)

    Failed to parse data (CBOR, JSON, or authenticator data).

  • InvalidAttestation(reason: String)

    The attestation format or statement is invalid.

  • InvalidSignature

    The cryptographic signature verification failed.

  • UserPresenceFailed

    User presence was required but not asserted by the authenticator.

  • UserVerificationFailed

    User verification was required but not performed by the authenticator.

The service using WebAuthn to register or authenticate users (i.e. your application).

pub type RelyingParty {
  RelyingParty(id: String, name: String)
}

Constructors

  • RelyingParty(id: String, name: String)

    Arguments

    id

    A domain string identifying the Relying Party ("example.com"). Do not include a scheme, port, or path. The browser validates the domain syntax and whether this RP ID is allowed for the calling origin.

    name

    A human-readable name shown to the user by the authenticator during registration.

Resident key (discoverable credential) requirement.

pub type ResidentKey {
  ResidentKeyDiscouraged
  ResidentKeyPreferred
  ResidentKeyRequired
}

Constructors

  • ResidentKeyDiscouraged

    The authenticator should not create a discoverable credential.

  • ResidentKeyPreferred

    The authenticator should create a discoverable credential if possible.

  • ResidentKeyRequired

    The authenticator must create a discoverable credential.

A parsed registration response. Construct via response_decoder (when the response arrives nested in a larger JSON envelope) or parse_response_json (when you have a raw response string). Pass to verify.

pub opaque type Response

User information for registration.

pub type User {
  User(id: BitArray, name: String, display_name: String)
}

Constructors

  • User(id: BitArray, name: String, display_name: String)

    Arguments

    id

    An opaque handle containing between 1 and 64 bytes, inclusive, that uniquely identifies the user to the authenticator. WebAuthn requires random bytes not derived from personal information (email, username, etc.), so authenticators cannot correlate the user across relying parties. Generate once per user with random_user_id and persist it alongside the account.

    name

    A human-readable identifier for the account, typically the login the user enters (username or email). Shown by the authenticator during account selection.

    display_name

    A human-readable name for the user (e.g. "Lucy"), intended only for display.

Values

pub fn algorithms(
  builder: Builder,
  algorithms: List(Algorithm),
) -> Result(Builder, Nil)

Replace the list of accepted signing algorithms, in preference order (the authenticator picks the first it supports). Returns Error(Nil) if the list is empty.

Defaults to [Es256] because it is the one algorithm every mainstream authenticator handles; opt in to Ed25519 or Rs256 when broader coverage is desired.

pub fn allow_cross_origin(
  builder: Builder,
  allow: Bool,
) -> Builder

Allow cross-origin requests. Defaults to disallowed.

pub fn allowed_top_origin(
  builder: Builder,
  origin: String,
) -> Builder

Add a top-level origin to the cross-origin iframe allowlist. The allowlist is consulted only when the browser supplies a topOrigin field; older browsers omit the field even for cross-origin requests, in which case top-origin verification is skipped.

pub fn authenticator_attachment(
  builder: Builder,
  attachment: AuthenticatorAttachment,
) -> Builder

Restrict authenticator type. Omitted by default (any authenticator).

pub fn build(builder: Builder) -> #(json.Json, Challenge)

Generate registration options and a challenge verifier from a builder.

The first element is a PublicKeyCredentialCreationOptionsJSON value ready to serialize or embed inside a response envelope. The second is the verifier to pass to verify.

pub fn encode_challenge(challenge: Challenge) -> String

Serialize a registration challenge for out-of-process storage between the build and verify steps (signed cookie, database, etc.). Pair with parse_challenge to rehydrate.

Security

The returned string is not authenticated. If an attacker can tamper with the stored blob they can redirect verification by forging rp_id or origins. Store it somewhere the caller controls (server-side session, a signed cookie, etc.).

pub fn exclude_credential(
  builder: Builder,
  id id: BitArray,
  transports transports: List(glasslock.Transport),
) -> Builder

Add a credential to the exclude_credentials list (prevent re-registration on this authenticator). Pass the stored credential’s id and transports so the browser can route the request.

pub fn new(
  relying_party relying_party: RelyingParty,
  user user: User,
  origin origin: String,
) -> Builder

Start a new registration request builder with the required fields.

Defaults: 1-minute timeout, ECDSA P-256 algorithm, no excluded credentials, cross-origin disallowed. Layer on optional configuration with the setter functions before calling build.

pub fn origin(builder: Builder, origin: String) -> Builder

Add an additional accepted origin. The origin passed to new is always included. The signed clientDataJSON.origin returned by the authenticator must match one of them exactly, so pass a serialized origin such as "https://example.com".

pub fn parse_challenge(
  encoded: String,
) -> Result(Challenge, Error)

Decode a previously-encoded registration challenge.

pub fn parse_response_json(
  response_json: String,
) -> Result(Response, Error)

Parse a raw response JSON string into a Response.

pub fn random_user_id() -> BitArray

Generate a random 16-byte WebAuthn user ID.

Generate one ID per account and persist it. Pass that same ID in later registration ceremonies for the account.

pub fn resident_key(
  builder: Builder,
  resident_key: ResidentKey,
) -> Builder

Set the discoverable credential requirement. When unset the field is omitted from the JSON sent to the browser, and the browser applies the spec default of discouraged.

pub fn response_decoder() -> decode.Decoder(Response)

Decoder for a registration response. Use when the response arrives nested in a larger JSON envelope.

pub fn timeout(
  builder: Builder,
  timeout: duration.Duration,
) -> Builder

Set the ceremony timeout. Defaults to 1 minute.

pub fn user_verification(
  builder: Builder,
  user_verification: glasslock.Verification,
) -> Builder

Set the user verification requirement. When unset the field is omitted from the JSON sent to the browser; the browser applies the spec default of preferred, and verify treats the policy as preferred.

pub fn verify(
  response response: Response,
  challenge challenge: Challenge,
) -> Result(glasslock.Credential, Error)

Verify a response from the browser.

Takes a parsed Response (from response_decoder or parse_response_json) and the challenge from build. Returns the verified credential on success.

pub fn verify_json(
  response_json response_json: String,
  challenge challenge: Challenge,
) -> Result(glasslock.Credential, Error)

Convenience wrapper around verify for callers whose response arrives as a raw JSON string: parses with parse_response_json then verifies.

Search Document