Documentation
¶
Overview ¶
Package webauthnadapter implements the credbound.PasskeyProvider port on top of github.com/go-webauthn/webauthn. Every ceremony requires user verification, so passkey authentication yields AAL2 directly, and user handles are HMAC-derived from the account ID so authenticators never learn stable Credbound identifiers.
Wire it into credbound.Config.Passkeys:
passkeys, err := webauthnadapter.New(webauthnadapter.Config{
RPID: "example.com",
RPDisplayName: "Example",
RPOrigins: []string{"https://app.example.com"},
UserHandleKey: key, // at least 32 secret bytes
})
Credbound seals the ceremony session into its continuation; the host only shuttles the JSON options and browser responses.
Index ¶
- type Config
- type Provider
- func (p *Provider) BeginAuthentication(ctx context.Context, input credbound.PasskeyUser) (json.RawMessage, []byte, error)
- func (p *Provider) BeginDecoyAuthentication(ctx context.Context, seed []byte) (json.RawMessage, []byte, error)
- func (p *Provider) BeginDiscoverableAuthentication(ctx context.Context) (json.RawMessage, []byte, error)
- func (p *Provider) BeginRegistration(ctx context.Context, input credbound.PasskeyUser) (json.RawMessage, []byte, error)
- func (p *Provider) FinishAuthentication(ctx context.Context, input credbound.PasskeyUser, rawSession, response []byte) ([]byte, []byte, error)
- func (p *Provider) FinishDiscoverableAuthentication(ctx context.Context, rawSession, response []byte, ...) ([]byte, []byte, error)
- func (p *Provider) FinishRegistration(ctx context.Context, input credbound.PasskeyUser, rawSession, response []byte) ([]byte, []byte, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// RPID is the relying-party identifier, normally the registrable
// domain (e.g. "example.com"). Changing it invalidates every
// registered passkey.
RPID string
// RPDisplayName is the human-readable relying-party name shown by
// authenticators during ceremonies.
RPDisplayName string
// RPOrigins lists the exact web origins allowed to complete
// ceremonies (e.g. "https://app.example.com"). Responses from any
// other origin are rejected.
RPOrigins []string
// UserHandleKey is a secret of at least 32 bytes used to HMAC user IDs
// into WebAuthn user handles. Keep it stable — rotating it orphans
// discoverable credentials — and never reuse another Credbound key.
UserHandleKey []byte
// MaxCredentials caps how many stored passkeys one user may present in
// a ceremony, 1 through 100. Zero defaults to 20.
MaxCredentials int
}
Config identifies the WebAuthn relying party and the key material used to derive user handles.
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider runs WebAuthn registration and authentication ceremonies with mandatory user verification. It is safe for concurrent use and implements credbound.PasskeyProvider.
func New ¶
New validates config and returns a Provider. A user handle key shorter than 32 bytes, an out-of-range credential cap or an invalid relying-party configuration is rejected.
func (*Provider) BeginAuthentication ¶
func (p *Provider) BeginAuthentication(ctx context.Context, input credbound.PasskeyUser) (json.RawMessage, []byte, error)
BeginAuthentication starts an assertion ceremony over the user's stored passkeys and returns the browser request options plus the opaque session. It fails when the user has no passkey.
func (*Provider) BeginDecoyAuthentication ¶
func (p *Provider) BeginDecoyAuthentication(ctx context.Context, seed []byte) (json.RawMessage, []byte, error)
BeginDecoyAuthentication fabricates a stable synthetic credential from the seed and runs the same assertion ceremony, so a caller cannot tell whether the address actually has a passkey. The seed is the manager's per-address digest; equal seeds yield an equal challenge shape across probes.
func (*Provider) BeginDiscoverableAuthentication ¶
func (p *Provider) BeginDiscoverableAuthentication(ctx context.Context) (json.RawMessage, []byte, error)
BeginDiscoverableAuthentication starts a usernameless assertion ceremony: the request options carry an empty allowCredentials list and the authenticator offers its resident (discoverable) credentials, so no per-account challenge exists to enumerate.
func (*Provider) BeginRegistration ¶
func (p *Provider) BeginRegistration(ctx context.Context, input credbound.PasskeyUser) (json.RawMessage, []byte, error)
BeginRegistration starts a passkey registration ceremony and returns the browser creation options plus the opaque session Credbound seals into the continuation.
func (*Provider) FinishAuthentication ¶
func (p *Provider) FinishAuthentication(ctx context.Context, input credbound.PasskeyUser, rawSession, response []byte) ([]byte, []byte, error)
FinishAuthentication validates the browser's assertion response against the sealed session and returns the matched credential ID and its updated JSON encoding (sign counter, flags) for persistence via TouchPasskey.
func (*Provider) FinishDiscoverableAuthentication ¶
func (p *Provider) FinishDiscoverableAuthentication(ctx context.Context, rawSession, response []byte, lookup credbound.PasskeyUserLookup) ([]byte, []byte, error)
FinishDiscoverableAuthentication validates the browser's assertion response, resolving the account through the lookup by the asserted credential ID and verifying the asserted user handle is the HMAC of that account's ID, so a tampered handle can never bind the assertion to a different user.
func (*Provider) FinishRegistration ¶
func (p *Provider) FinishRegistration(ctx context.Context, input credbound.PasskeyUser, rawSession, response []byte) ([]byte, []byte, error)
FinishRegistration validates the browser's attestation response against the sealed session and returns the new credential ID and its JSON encoding for storage.