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
-
Es256ECDSA with P-256 curve and SHA-256 hash (COSE algorithm -7).
-
Ed25519EdDSA with Ed25519 curve (COSE algorithm -8).
-
Rs256RSASSA-PKCS1-v1_5 with SHA-256 (COSE algorithm -257).
Authenticator attachment preference.
pub type AuthenticatorAttachment {
Platform
CrossPlatform
}
Constructors
-
PlatformPlatform authenticator (e.g., Touch ID, Windows Hello).
-
CrossPlatformRoaming authenticator (e.g., USB security key, Bluetooth).
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.
-
InvalidSignatureThe cryptographic signature verification failed.
-
UserPresenceFailedUser presence was required but not asserted by the authenticator.
-
UserVerificationFailedUser 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
-
ResidentKeyDiscouragedThe authenticator should not create a discoverable credential.
-
ResidentKeyPreferredThe authenticator should create a discoverable credential if possible.
-
ResidentKeyRequiredThe 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_idand 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.