Documentation
¶
Overview ¶
Package webauthn implements a bounded WebAuthn Level 3 none-attestation, ES256 or explicitly selected Ed25519 protocol profile. It does not authorize identity enrollment or issue sessions. Trusted workflows authorize context first.
Index ¶
- type Algorithm
- type AssertionMutation
- type AssertionOptions
- type AssertionTransition
- type BeginAssertionRequest
- type BeginDiscoverableAssertionRequest
- type BeginRegistrationRequest
- type CeremonyContext
- type CeremonyCreation
- type CeremonyIntent
- type CeremonyRecord
- type Challenge
- type ChallengeDigestKey
- type Config
- type Conflict
- type Credential
- type CredentialPropertiesOutput
- type CredentialProtectionOutput
- type Denied
- type Dependencies
- type DiscoverableService
- type DiscoverableStore
- type ExtensionAuthority
- type ExtensionOutputSet
- type ExtensionRequestSet
- type Invalid
- type Lookup
- type Operation
- type RecoveryRequest
- type RegistrationMutation
- type RegistrationOptions
- type RegistrationTransition
- type RelyingParty
- type Replay
- type Service
- type Store
- type Unavailable
- type UnknownCommit
- type VerificationContext
- type VerifiedAssertion
- type VerifiedRegistration
- type VerifyAssertionRequest
- type VerifyDiscoverableAssertionRequest
- type VerifyRegistrationRequest
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Algorithm ¶
type Algorithm int32
Algorithm identifies one supported COSE signature algorithm and exact key profile. Other COSE values, including other EdDSA curves, are unsupported.
type AssertionMutation ¶
type AssertionMutation struct {
Context CeremonyContext
Ceremony CeremonyRecord
Before Credential
After Credential
ResponseDigest [32]byte
CounterRisk bool
}
AssertionMutation fixes the exact verified before/after credential state. CounterRisk is bounded risk evidence for backup-eligible counter regressions; it is not an automatic clone verdict. Counter never decreases.
type AssertionOptions ¶
type AssertionOptions struct {
// contains filtered or unexported fields
}
AssertionOptions contains identified-assertion browser options after commit.
func (AssertionOptions) Ceremony ¶
func (o AssertionOptions) Ceremony() (CeremonyRecord, bool)
Ceremony returns safe original assertion metadata, never authentication.
func (AssertionOptions) TransferJSON ¶
func (o AssertionOptions) TransferJSON(ctx context.Context, deliver func(context.Context, []byte) error) error
TransferJSON delivers bounded browser assertion options exactly once.
type AssertionTransition ¶
type AssertionTransition struct {
// contains filtered or unexported fields
}
AssertionTransition is immutable verified-signature input to atomic storage. Store must compare the original versions, not rebase a stale assertion.
func (AssertionTransition) Mutation ¶
func (t AssertionTransition) Mutation() (AssertionMutation, error)
Mutation returns the original verified optimistic transition, never a rebase.
type BeginAssertionRequest ¶
type BeginAssertionRequest struct {
Context CeremonyContext
UserHandle []byte
Origin string
AllowedCredentials [][]byte
}
BeginAssertionRequest selects an existing identified subject and a nonempty allowlist of at most 100 credentials. Use DiscoverableService for usernameless.
type BeginDiscoverableAssertionRequest ¶
type BeginDiscoverableAssertionRequest struct {
Context CeremonyContext
Origin string
}
BeginDiscoverableAssertionRequest requires an empty Context.UserID and a trusted bounded Context.AnonymousFlowID. No user handle or allowlist is known.
type BeginRegistrationRequest ¶
type BeginRegistrationRequest struct {
Context CeremonyContext
UserHandle []byte
Origin string
ExcludedCredentials [][]byte
ResidentKeyRequired bool
}
BeginRegistrationRequest fixes the opaque 32-byte RP-wide user handle and exact allowed origin. The trusted caller owns prior identity authorization. ResidentKeyRequired opts into resident-required browser creation; false keeps the existing discouraged profile. Neither none attestation nor credProps proves physical residency or authenticator provenance.
type CeremonyContext ¶
type CeremonyContext struct {
CommandID identity.CommandID
TenantID identity.TenantID
UserID identity.UserID
// AnonymousFlowID selects a trusted pre-authentication transaction only for
// discoverable assertions. It is mutually exclusive with UserID.
AnonymousFlowID string `json:",omitempty"`
ActorID identity.ActorID
CorrelationID string
}
CeremonyContext comes from an already authorized trusted workflow, never Host, forwarded headers or a browser body. It is not proof of identity or a session. Use a fresh identity.NewCommandID for each operation and retain it on retries.
type CeremonyCreation ¶
type CeremonyCreation struct {
// contains filtered or unexported fields
}
CeremonyCreation is issued only by Service. Its immutable intent can be read by a durable adapter; Generate runs only after acknowledged command ownership, outside SQL. Generated challenge is an output, not a caller-supplied input. Raw challenge custody must never enter retained preparation or journal data.
func (CeremonyCreation) Generate ¶
func (c CeremonyCreation) Generate(ctx context.Context, now time.Time) (CeremonyRecord, Challenge, error)
Generate creates original challenge output with crypto/rand outside SQL. Adapters call this only after acknowledged command reservation. now is a primary-authority clock sample. The digest binds complete ceremony scope.
func (CeremonyCreation) Intent ¶
func (c CeremonyCreation) Intent() (CeremonyIntent, error)
Intent returns an owned copy of every original caller-controlled input.
type CeremonyIntent ¶
type CeremonyIntent struct {
Context CeremonyContext
Kind string
RPID string
RPVersion uint64
Origin string
UserHandle []byte
AllowedCredentials [][]byte
Extensions ExtensionRequestSet
// ResidentKeyRequired selects resident-required creation, never a claim
// that an unsigned browser extension proves authenticator residency.
ResidentKeyRequired bool `json:",omitempty"`
// Algorithms freezes the exact explicit profile. Absent means legacy ES256,
// never the current service's expanded policy. Omission preserves old rows.
Algorithms []Algorithm `json:",omitempty"`
}
CeremonyIntent is the complete safe generated-state request. Challenge bytes are deliberately absent. Consumers must not log opaque handles or user data. Policy fields are frozen by the service, not recovered from browser input.
type CeremonyRecord ¶
type CeremonyRecord struct {
Intent CeremonyIntent
ID string
ChallengeDigest [32]byte
ExpiresAt time.Time
Version uint64
}
CeremonyRecord contains only a scoped keyed challenge digest at rest. Versions start at 1. Store queries bind tenant/RP/ceremony and subject or pre-auth flow.
type Challenge ¶
type Challenge struct {
// contains filtered or unexported fields
}
Challenge is opaque reveal-once custody. Only Transfer exposes bytes to a synchronous browser-delivery callback outside database work. Copies share lifetime; diagnostics and serialization never expose bytes. Zero is invalid.
func (Challenge) Discard ¶
func (c Challenge) Discard()
Discard invalidates every alias and clears unrevealed bytes, including on unknown commit paths. It performs no IO and is safe beside Transfer.
func (Challenge) MarshalJSON ¶
func (Challenge) Transfer ¶
func (c Challenge) Transfer(ctx context.Context, deliver func(context.Context, []byte) error) (err error)
Transfer invalidates every challenge alias before calling deliver. Borrowed bytes are cleared afterward, including errors and panics. Delivery failure does not undo a committed ceremony and never permits re-reveal on retry.
type ChallengeDigestKey ¶
type ChallengeDigestKey struct {
// contains filtered or unexported fields
}
ChallengeDigestKey is immutable opaque deployment-key custody. Its closure representation also protects keys inside unexported enclosing fmt wrappers. The caller retains responsibility for its original input copy. Zero is invalid.
func NewChallengeDigestKey ¶
func NewChallengeDigestKey(input []byte) (ChallengeDigestKey, error)
NewChallengeDigestKey copies a nonzero exact 32-byte key without IO.
func (ChallengeDigestKey) MarshalJSON ¶
func (ChallengeDigestKey) MarshalJSON() ([]byte, error)
type Config ¶
type Config struct {
TenantID identity.TenantID
RelyingParty RelyingParty
Extensions ExtensionRequestSet
// Algorithms is an ordered, copied allowlist used for both ceremonies.
// Nil preserves the legacy ES256-only profile and stored ceremony bytes.
// An explicit list must be nonempty, unique and limited to ES256/EdDSA.
// Changing it invalidates in-flight ceremonies; also advance RP.Version.
Algorithms []Algorithm
ChallengeKey ChallengeDigestKey
DevelopmentLocalhostHTTP bool
MaximumDuration time.Duration
}
Config selects one trusted tenant and one RP. This finite profile always requires UP and UV, none attestation, and a five-minute 32-byte challenge. ChallengeKey is a nonzero deployment-owned HMAC key; keep it stable while ceremonies exist. The service copies it and never serializes it.
func (Config) MarshalJSON ¶
type Conflict ¶
type Conflict struct{}
Conflict identifies optimistic, idempotency or RP-wide uniqueness conflicts.
type Credential ¶
type Credential struct {
TenantID identity.TenantID
UserID identity.UserID
RPID string
ID []byte
UserHandle []byte
PublicKey []byte
Algorithm int32
AAGUID [16]byte
Counter uint32
BackupEligible bool
BackupState bool
Extensions ExtensionOutputSet
Version uint64
}
Credential is public verification metadata, never authentication evidence. Byte slices are owned snapshots. Version is positive and monotonically grows. Credential IDs/user-handle mappings are unique across the whole RP, not tenant.
type CredentialPropertiesOutput ¶
type CredentialPropertiesOutput struct {
ResidentKey bool
Authority ExtensionAuthority
}
CredentialPropertiesOutput is an untrusted browser claim, never signed authenticator authority and never sufficient to authorize a policy decision.
type CredentialProtectionOutput ¶
type CredentialProtectionOutput struct {
Policy uint8
Authority ExtensionAuthority
}
CredentialProtectionOutput records creation authenticator data. Registration with none attestation provides no device provenance. Assertions preserve this metadata, never promoting unsolicited output into fresh enrollment authority.
type Denied ¶
type Denied struct{}
Denied intentionally does not distinguish missing, expired or wrong-scope state.
type Dependencies ¶
type Dependencies struct{ Store Store }
Dependencies are borrowed, concurrent-safe dependencies; the service never closes them. Store must be a durable participant, not an application map.
type DiscoverableService ¶
type DiscoverableService interface {
Service
BeginDiscoverableAssertion(context.Context, BeginDiscoverableAssertionRequest) (AssertionOptions, error)
VerifyDiscoverableAssertion(context.Context, VerifyDiscoverableAssertionRequest) (VerifiedAssertion, error)
}
DiscoverableService adds resident-required registration/usernameless assertion without changing the identified Service or Store contracts. Results remain protocol facts, not identity enrollment grants, sessions or authorization.
func NewDiscoverable ¶
func NewDiscoverable(c Config, d Dependencies) (DiscoverableService, error)
NewDiscoverable selects usernameless assertions only with the explicit durable resolution contract. It otherwise has the same bounded configuration as New.
type DiscoverableStore ¶
type DiscoverableStore interface {
Store
LoadDiscoverableCredential(context.Context, Lookup, []byte, []byte) (Credential, error)
}
DiscoverableStore is the optional durable resolution seam. Lookup must carry an anonymous context and the original ceremony. Resolve exactly RP, credential ID and mandatory handle, scope tenant without disambiguating RP uniqueness, and preserve original pre-transition state for exact retries. FinalizeAssertion must check the resolved active subject inside its atomic commit, consume the anonymous ceremony and CAS-update that same credential and handle mapping.
type ExtensionAuthority ¶
type ExtensionAuthority uint8
ExtensionAuthority prevents retained browser/none-attestation claims from being promoted to fresh signed authenticator evidence by downstream callers.
const ( // BrowserReported is unsigned client-extension output, never authorization. BrowserReported ExtensionAuthority = iota + 1 // UnattestedAuthenticator is structurally accepted registration authData // under none attestation, without authenticator provenance/signature trust. UnattestedAuthenticator )
type ExtensionOutputSet ¶
type ExtensionOutputSet struct {
CredentialProperties *CredentialPropertiesOutput
CredentialProtection *CredentialProtectionOutput
}
ExtensionOutputSet retains only explicitly requested typed outputs. Unknown and unselected extensions are discarded without persistence or advertisement.
type ExtensionRequestSet ¶
type ExtensionRequestSet struct {
CredentialProperties bool
CredentialProtection uint8
EnforceCredentialProtection bool
}
ExtensionRequestSet selects creation-only credProps and credProtect. Zero requests neither. CredentialProtection is 0 (absent) or FIDO values 1, 2 or 3. Assertions retain this frozen policy but emit no creation-only inputs.
type Invalid ¶
type Invalid struct{ Field string }
Invalid is a redacted structural/configuration error. Field is a static name.
type Lookup ¶
type Lookup struct {
Context CeremonyContext
RPID string
CeremonyID string
}
Lookup carries exact trusted tenant/RP/ceremony and subject or pre-auth flow.
type Operation ¶
type Operation uint8
Operation is the closed recoverable native operation. Zero is invalid.
const ( // BeginRegistrationOperation recovers original challenge creation metadata. BeginRegistrationOperation Operation = iota + 1 // BeginAssertionOperation recovers original assertion creation metadata. BeginAssertionOperation // RegistrationOperation recovers original credential creation. RegistrationOperation // AssertionOperation recovers original counter/backup update. AssertionOperation // BeginDiscoverableAssertionOperation recovers anonymous ceremony creation. BeginDiscoverableAssertionOperation // DiscoverableAssertionOperation recovers anonymous credential finalization. DiscoverableAssertionOperation )
type RecoveryRequest ¶
type RecoveryRequest struct {
Context CeremonyContext
Operation Operation
CredentialID []byte
}
RecoveryRequest retains exact original command scope, including anonymous flow for discoverable operations. CredentialID is required only for completion. Recovery returns safe historical outcome, never a challenge, Verified result or renewed authentication proof.
type RegistrationMutation ¶
type RegistrationMutation struct {
Context CeremonyContext
Ceremony CeremonyRecord
Credential Credential
ResponseDigest [32]byte
}
RegistrationMutation is a copied native-adapter projection, not authority to construct a RegistrationTransition or bypass the public verifier.
type RegistrationOptions ¶
type RegistrationOptions struct {
// contains filtered or unexported fields
}
RegistrationOptions contains JSON browser options plus opaque challenge custody. TransferJSON emits a fresh challenge only once after durable creation.
func (RegistrationOptions) Ceremony ¶
func (o RegistrationOptions) Ceremony() (CeremonyRecord, bool)
Ceremony returns safe original metadata, including for a committed retry whose reveal-once challenge is unavailable. It does not expose challenge data.
func (RegistrationOptions) TransferJSON ¶
func (o RegistrationOptions) TransferJSON(ctx context.Context, deliver func(context.Context, []byte) error) error
TransferJSON delivers bounded browser creation options exactly once. The callback owns any explicit copy and must not log its challenge-bearing input.
type RegistrationTransition ¶
type RegistrationTransition struct {
// contains filtered or unexported fields
}
RegistrationTransition is immutable protocol-verifier output. Only Service can create it. It is provisional and not an authenticated result; native adapters consume the ceremony and create Credential in one coordinated commit.
func (RegistrationTransition) Mutation ¶
func (t RegistrationTransition) Mutation() (RegistrationMutation, error)
Mutation returns an owned provisional native projection. Zero transitions cannot be reconstructed from public fields; only the verifier issues them.
type RelyingParty ¶
RelyingParty is fixed before processing browser input. Version changes when any RP/origin/extension policy changes; old ceremonies cannot be reinterpreted. TenantID is selected before RP lookup. Shared-RP mappings are not yet selected.
type Replay ¶
Replay reports historical commitment without issuing fresh verification or challenge custody. Recover returns the original safe command outcome.
type Service ¶
type Service interface {
BeginRegistration(context.Context, BeginRegistrationRequest) (RegistrationOptions, error)
BeginAssertion(context.Context, BeginAssertionRequest) (AssertionOptions, error)
VerifyRegistration(context.Context, VerifyRegistrationRequest) (VerifiedRegistration, error)
VerifyAssertion(context.Context, VerifyAssertionRequest) (VerifiedAssertion, error)
Recover(context.Context, RecoveryRequest) (identity.CommitOutcome, error)
}
Service owns the selected complete protocol path, never session or passkey UX.
type Store ¶
type Store interface {
CreateCeremony(context.Context, CeremonyCreation) (CeremonyRecord, Challenge, identity.CommitOutcome, error)
LoadCeremony(context.Context, Lookup) (CeremonyRecord, error)
LoadCredential(context.Context, Lookup, []byte) (Credential, error)
FinalizeRegistration(context.Context, RegistrationTransition) (Credential, identity.CommitOutcome, error)
FinalizeAssertion(context.Context, AssertionTransition) (Credential, identity.CommitOutcome, error)
Recover(context.Context, RecoveryRequest) (identity.CommitOutcome, error)
}
Store is the storage-neutral complete ceremony/credential participant seam. No method exposes a concrete coordinator, transaction, or identity.UnitOfWork. Create may call Generate only after reservation is acknowledged and outside SQL. It reveals challenge custody only for acknowledged first commit; retries return original safe record and zero challenge. Finalize methods atomically consume the exact ceremony/version and insert or update credential, together with mandatory audit/lifecycle and the original command receipt. Unknown outcomes return no credential, no challenge and no verified result. All methods must support concurrent bounded calls and preserve tenant scope.
type Unavailable ¶
type Unavailable struct{}
Unavailable is a redacted dependency failure, never evidence of rollback.
func (Unavailable) Error ¶
func (Unavailable) Error() string
type UnknownCommit ¶
UnknownCommit requires recovery of this exact original command, not a new ID.
func (UnknownCommit) Error ¶
func (UnknownCommit) Error() string
type VerificationContext ¶
type VerificationContext struct {
Command CeremonyContext
CeremonyID string
Operation Operation
RPID string
RPVersion uint64
Origin string
ExpiresAt time.Time
UserPresent bool
UserVerified bool
}
VerificationContext preserves the exact original finalized ceremony and completion command. ExpiresAt is the original absolute ceremony ceiling, never a new validity lease. These are historical protocol facts; consumers still require their owning identity/current-authority and factor policy.
type VerifiedAssertion ¶
type VerifiedAssertion struct {
// contains filtered or unexported fields
}
VerifiedAssertion can only be issued after signature checks and durable challenge consumption/counter/backup update. Copies cannot renew authority.
func (VerifiedAssertion) Context ¶
func (v VerifiedAssertion) Context() (VerificationContext, bool)
Context returns original immutable ceremony/command facts, not fresh authority.
func (VerifiedAssertion) CounterRisk ¶
func (v VerifiedAssertion) CounterRisk() bool
CounterRisk reports a selected backup-credential counter warning only after successful finalization. False also represents an invalid zero result.
func (VerifiedAssertion) Credential ¶
func (v VerifiedAssertion) Credential() (Credential, bool)
Credential returns owned finalized metadata and false for the invalid zero.
type VerifiedRegistration ¶
type VerifiedRegistration struct {
// contains filtered or unexported fields
}
VerifiedRegistration can only be issued after successful durable finalization. It is WebAuthn protocol evidence, not a principal, session or enrollment grant.
func (VerifiedRegistration) Context ¶
func (v VerifiedRegistration) Context() (VerificationContext, bool)
Context returns original immutable ceremony/command facts, not fresh authority.
func (VerifiedRegistration) Credential ¶
func (v VerifiedRegistration) Credential() (Credential, bool)
Credential returns owned finalized metadata and false for the invalid zero.
type VerifyAssertionRequest ¶
type VerifyAssertionRequest struct {
Context CeremonyContext
CeremonyID string
Origin string
Response []byte
ExpectedVersion uint64
ExpectedCredentialVersion uint64
}
VerifyAssertionRequest additionally pins the observed credential version.
type VerifyDiscoverableAssertionRequest ¶
type VerifyDiscoverableAssertionRequest struct {
Context CeremonyContext
CeremonyID string
Origin string
Response []byte
ExpectedVersion uint64
}
VerifyDiscoverableAssertionRequest retains the exact original pre-auth flow. Credential version is read from primary storage and atomically compared; the browser cannot choose a subject, handle mapping or expected credential version.
type VerifyRegistrationRequest ¶
type VerifyRegistrationRequest struct {
Context CeremonyContext
CeremonyID string
Origin string
Response []byte
ExpectedVersion uint64
}
VerifyRegistrationRequest is bounded raw browser JSON, not verified evidence. Context.CommandID is distinct from the creation command and stable on retry.