Documentation
¶
Index ¶
- Constants
- Variables
- func GetAuthenticatorName(aaguid *string) string
- type AfterAuthenticationHook
- type AfterRegistrationHook
- type AuthenticationFailedPayload
- type AuthenticationOptionsCreatedPayload
- type AuthenticationOptionsResult
- type AuthenticationVerifiedPayload
- type CeremonyType
- type Config
- type DeletePasskeyParams
- type GenerateAuthenticationOptionsParams
- type GenerateRegistrationOptionsParams
- type ListPasskeysParams
- type Option
- func WithAfterAuthentication(hook AfterAuthenticationHook) Option
- func WithAfterRegistration(hook AfterRegistrationHook) Option
- func WithAttestation(att protocol.ConveyancePreference) Option
- func WithAuthenticatorAttachment(attachment protocol.AuthenticatorAttachment) Option
- func WithChallengeTimeout(d time.Duration) Option
- func WithRPDisplayName(name string) Option
- func WithRPID(rpID string) Option
- func WithRPOrigins(origins ...string) Option
- func WithRequireSessionOnRegistration(require bool) Option
- func WithResidentKey(rk protocol.ResidentKeyRequirement) Option
- func WithResolveUser(fn ResolveUserFunc) Option
- func WithSessionDuration(d time.Duration) Option
- func WithUserVerification(uv protocol.UserVerificationRequirement) Option
- type PasskeyChallenge
- type PasskeyDeletedPayload
- type PasskeyRegistrationUser
- type PasskeyUpdatedPayload
- type Plugin
- func (p *Plugin) Config() Config
- func (p *Plugin) DeletePasskey(ctx context.Context, params *DeletePasskeyParams) error
- func (p *Plugin) GenerateAuthenticationOptions(ctx context.Context, params *GenerateAuthenticationOptionsParams) (*AuthenticationOptionsResult, error)
- func (p *Plugin) GenerateRegistrationOptions(ctx context.Context, params *GenerateRegistrationOptionsParams) (*RegistrationOptionsResult, error)
- func (p *Plugin) GetPasskey(ctx context.Context, id string) (*entity.Passkey, error)
- func (p *Plugin) ID() string
- func (p *Plugin) Init(ctx *plugin.Context) error
- func (p *Plugin) ListPasskeys(ctx context.Context, params *ListPasskeysParams) ([]*entity.Passkey, error)
- func (p *Plugin) UpdatePasskey(ctx context.Context, params *UpdatePasskeyParams) (*entity.Passkey, error)
- func (p *Plugin) VerifyAuthentication(ctx context.Context, params *VerifyAuthenticationParams) (*VerifyAuthenticationResult, error)
- func (p *Plugin) VerifyRegistration(ctx context.Context, params *VerifyRegistrationParams) (*entity.Passkey, error)
- type RegistrationFailedPayload
- type RegistrationOptionsCreatedPayload
- type RegistrationOptionsResult
- type RegistrationVerifiedPayload
- type Repository
- type ResolveUserFunc
- type UpdatePasskeyParams
- type VerifyAuthenticationParams
- type VerifyAuthenticationResult
- type VerifyRegistrationParams
Constants ¶
const ( EventRegistrationOptionsCreated = "passkey:registration_options:created" EventRegistrationVerified = "passkey:registration:verified" EventRegistrationFailed = "passkey:registration:failed" EventAuthenticationOptionsCreated = "passkey:authentication_options:created" EventAuthenticationVerified = "passkey:authentication:verified" EventAuthenticationFailed = "passkey:authentication:failed" EventPasskeyUpdated = "passkey:updated" EventPasskeyDeleted = "passkey:deleted" )
Event topic names for Passkey lifecycle events published to the EventBus.
const ( ExtraKeyOrigin = "origin" ExtraKeyAAGUID = "aaguid" ExtraKeyDeviceType = "deviceType" ExtraKeyTransports = "transports" ExtraKeyChallengeToken = "challengeToken" ExtraKeyUserAgent = "userAgent" ExtraKeyIPAddress = "ipAddress" )
Metadata keys for extra context passed in parameters or event payloads.
const ( StoreKeyRPID = "passkey:rp_id" StoreKeyRPOrigins = "passkey:rp_origins" StoreKeyRPName = "passkey:rp_name" StoreKeyActiveCount = "passkey:active_count" )
Shared context storage keys for plugin.Context.
const AnonymousAAGUID = "00000000-0000-0000-0000-000000000000"
AnonymousAAGUID represents the zero/anonymous AAGUID indicating an unauthenticated or privacy-preserving model.
Variables ¶
var ( ErrPasskeyNotFound = errors.New("passkey: passkey not found") ErrPasskeyAlreadyExists = errors.New("passkey: passkey credential already registered") ErrChallengeNotFound = errors.New("passkey: challenge not found or expired") ErrChallengeExpired = errors.New("passkey: challenge has expired") ErrInvalidCeremonyType = errors.New("passkey: invalid ceremony type for this challenge") ErrVerificationFailed = errors.New("passkey: failed to verify webauthn ceremony response") ErrCounterNotIncremented = errors.New("passkey: signature counter did not increment (possible authenticator clone)") ErrUserNotFound = errors.New("passkey: user not found") ErrSessionRequired = errors.New("passkey: passkey registration requires an authenticated session") ErrResolveUserRequired = errors.New("passkey: resolveUser callback is required when requireSession is false and no session exists") ErrInvalidResolvedUser = errors.New("passkey: resolved user is invalid") ErrOriginMissing = errors.New("passkey: origin is missing in request context") ErrInvalidParameter = errors.New("passkey: invalid parameter provided") ErrUnableToCreateSession = errors.New("passkey: unable to create user session") ErrFailedToUpdatePasskey = errors.New("passkey: failed to update passkey") )
Sentinel errors for the Passkey plugin.
var CommonAuthenticatorNames = map[string]string{
"ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4": "Google Password Manager",
"fbfc3007-154e-4ecc-8c0b-6e020557d7bd": "Apple Passwords",
"dd4ec289-e01d-41c9-bb89-70fa845d4bf2": "iCloud Keychain (Managed)",
"08987058-cadc-4b81-b6e1-30de50dcbe96": "Windows Hello",
"9ddd1817-af5a-4672-a2b9-3e3dd95000a9": "Windows Hello",
"6028b017-b1d4-4c02-b4b3-afcdafc96bb2": "Windows Hello",
"bada5566-a7aa-401f-bd96-45619a55120d": "1Password",
"d548826e-79b4-db40-a3d8-11116f7e8349": "Bitwarden",
"531126d6-e717-415c-9320-3d9aa6981239": "Dashlane",
"b78a0a55-6ef8-d246-a042-ba0f6d55050c": "LastPass",
"b84e4048-15dc-4dd0-8640-f4f60813c8af": "NordPass",
"50726f74-6f6e-5061-7373-50726f746f6e": "Proton Pass",
"0ea242b4-43c4-4a1b-8b17-dd6d0b6baec6": "Keeper",
"53414d53-554e-4700-0000-000000000000": "Samsung Pass",
"cb69481e-8ff7-4039-93ec-0a2729a1ef67": "YubiKey 5 Series",
"ee882879-721c-4916-956b-f40570e30973": "YubiKey 5 NFC",
"fa2b99dc-9e39-4257-8f92-4a30d23c4118": "YubiKey 5C NFC",
}
CommonAuthenticatorNames maps known Authenticator Attestation GUIDs (AAGUID) to human-friendly provider names.
Functions ¶
func GetAuthenticatorName ¶
GetAuthenticatorName returns the descriptive name of an authenticator given its AAGUID, or "Passkey" as fallback.
Types ¶
type AfterAuthenticationHook ¶
type AfterAuthenticationHook func(ctx context.Context, passkey *entity.Passkey, user *entity.User, session *entity.Session) error
AfterAuthenticationHook is executed after a passkey assertion is verified and a new session created.
type AfterRegistrationHook ¶
type AfterRegistrationHook func(ctx context.Context, passkey *entity.Passkey, user *entity.User) error
AfterRegistrationHook is executed after a new passkey credential has been successfully verified and saved.
type AuthenticationFailedPayload ¶
type AuthenticationFailedPayload struct {
UserID *string `json:"userId,omitempty"`
ChallengeToken string `json:"challengeToken"`
Reason string `json:"reason"`
Extra map[string]any `json:"extra,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
AuthenticationFailedPayload is dispatched when an authentication assertion fails.
type AuthenticationOptionsCreatedPayload ¶
type AuthenticationOptionsCreatedPayload struct {
UserID *string `json:"userId,omitempty"`
ChallengeToken string `json:"challengeToken"`
ExpiresAt time.Time `json:"expiresAt"`
Extra map[string]any `json:"extra,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
AuthenticationOptionsCreatedPayload is dispatched when an authentication assertion challenge is created.
type AuthenticationOptionsResult ¶
type AuthenticationOptionsResult struct {
Options *protocol.CredentialAssertion `json:"options"`
ChallengeToken string `json:"challengeToken"`
ExpiresAt time.Time `json:"expiresAt"`
}
AuthenticationOptionsResult contains assertion request options and the tracking challenge token.
type AuthenticationVerifiedPayload ¶
type AuthenticationVerifiedPayload struct {
Passkey *entity.Passkey `json:"passkey"`
User *entity.User `json:"user"`
Session *entity.Session `json:"session"`
Extra map[string]any `json:"extra,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
AuthenticationVerifiedPayload is dispatched when a passkey assertion is verified and session created.
type CeremonyType ¶
type CeremonyType string
CeremonyType defines the type of WebAuthn ceremony.
const ( CeremonyRegistration CeremonyType = "registration" CeremonyAuthentication CeremonyType = "authentication" )
type Config ¶
type Config struct {
RPDisplayName string // Relying Party human-readable name (default: "GoModularAuth")
RPID string // Relying Party domain identifier (default: "localhost")
RPOrigins []string // Allowed origin URLs (e.g. "http://localhost:3000")
ChallengeTimeout time.Duration // Ephemeral challenge lifespan (default: 5 minutes)
RequireSessionOnRegistration bool // Enforce caller session during registration (default: true)
UserVerification protocol.UserVerificationRequirement // User verification requirement (default: "preferred")
ResidentKey protocol.ResidentKeyRequirement // Resident key / Discoverable credential preference (default: "preferred")
Attestation protocol.ConveyancePreference // Attestation conveyance preference (default: "none")
AuthenticatorAttachment *protocol.AuthenticatorAttachment // Optional attachment ("platform" or "cross-platform")
SessionDuration time.Duration // Lifespan of created user sessions (default: 7 days)
ResolveUser ResolveUserFunc // User resolution callback
AfterRegistration AfterRegistrationHook // Post-registration hook
AfterAuthentication AfterAuthenticationHook // Post-authentication hook
}
Config holds runtime configuration options for the Passkey plugin.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config populated with production-ready defaults.
type DeletePasskeyParams ¶
DeletePasskeyParams contains deletion parameters for an existing passkey.
type GenerateAuthenticationOptionsParams ¶
type GenerateAuthenticationOptionsParams struct {
UserID *string `json:"userId,omitempty"` // Optional. Omit for discoverable/resident key/autofill login.
Extra map[string]any `json:"extra,omitempty"`
}
GenerateAuthenticationOptionsParams holds inputs for creating a WebAuthn assertion ceremony challenge.
type GenerateRegistrationOptionsParams ¶
type GenerateRegistrationOptionsParams struct {
UserID string `json:"userId,omitempty"`
UserName string `json:"userName,omitempty"`
UserDisplayName string `json:"userDisplayName,omitempty"`
AuthenticatorAttachment *protocol.AuthenticatorAttachment `json:"authenticatorAttachment,omitempty"`
Context *string `json:"context,omitempty"`
CustomName *string `json:"customName,omitempty"`
Extra map[string]any `json:"extra,omitempty"`
}
GenerateRegistrationOptionsParams holds inputs for creating a WebAuthn credential registration ceremony challenge.
type ListPasskeysParams ¶
type ListPasskeysParams struct {
UserID string `json:"userId"`
}
ListPasskeysParams filters passkeys for a specific user.
type Option ¶
type Option func(*Config)
Option configures the Passkey plugin.
func WithAfterAuthentication ¶
func WithAfterAuthentication(hook AfterAuthenticationHook) Option
WithAfterAuthentication sets the post-authentication lifecycle hook.
func WithAfterRegistration ¶
func WithAfterRegistration(hook AfterRegistrationHook) Option
WithAfterRegistration sets the post-registration lifecycle hook.
func WithAttestation ¶
func WithAttestation(att protocol.ConveyancePreference) Option
WithAttestation sets the attestation conveyance preference.
func WithAuthenticatorAttachment ¶
func WithAuthenticatorAttachment(attachment protocol.AuthenticatorAttachment) Option
WithAuthenticatorAttachment restricts authenticators to platform or cross-platform devices.
func WithChallengeTimeout ¶
WithChallengeTimeout sets the validity duration for ephemeral challenges.
func WithRPDisplayName ¶
WithRPDisplayName sets the Relying Party human-readable name.
func WithRPID ¶
WithRPID sets the Relying Party domain identifier (e.g. "auth.example.com" or "localhost").
func WithRPOrigins ¶
WithRPOrigins sets the list of allowed origin URLs.
func WithRequireSessionOnRegistration ¶
WithRequireSessionOnRegistration toggles whether registration requires an active authenticated caller.
func WithResidentKey ¶
func WithResidentKey(rk protocol.ResidentKeyRequirement) Option
WithResidentKey sets the resident key (discoverable credential) preference.
func WithResolveUser ¶
func WithResolveUser(fn ResolveUserFunc) Option
WithResolveUser sets the callback to resolve user identity during unauthenticated registration flows.
func WithSessionDuration ¶
WithSessionDuration sets the validity duration for sessions issued upon successful authentication.
func WithUserVerification ¶
func WithUserVerification(uv protocol.UserVerificationRequirement) Option
WithUserVerification sets the WebAuthn user verification preference.
type PasskeyChallenge ¶
type PasskeyChallenge struct {
Token string `json:"token"`
Type CeremonyType `json:"type"`
Challenge string `json:"challenge"`
UserID *string `json:"userId,omitempty"`
UserName *string `json:"userName,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
Context *string `json:"context,omitempty"`
SessionData string `json:"sessionData"` // Serialized JSON of webauthn.SessionData
ExpiresAt time.Time `json:"expiresAt"`
CreatedAt time.Time `json:"createdAt"`
}
PasskeyChallenge represents the ephemeral state of an in-flight WebAuthn challenge.
type PasskeyDeletedPayload ¶
type PasskeyDeletedPayload struct {
PasskeyID string `json:"passkeyId"`
UserID string `json:"userId"`
Timestamp time.Time `json:"timestamp"`
}
PasskeyDeletedPayload is dispatched when a passkey is deleted.
type PasskeyRegistrationUser ¶
type PasskeyRegistrationUser struct {
ID string `json:"id"`
Name string `json:"name"`
DisplayName string `json:"displayName"`
}
PasskeyRegistrationUser represents a resolved user identity when registering without an active session.
type PasskeyUpdatedPayload ¶
type PasskeyUpdatedPayload struct {
Passkey *entity.Passkey `json:"passkey"`
OldName *string `json:"oldName,omitempty"`
NewName string `json:"newName"`
Timestamp time.Time `json:"timestamp"`
}
PasskeyUpdatedPayload is dispatched when a passkey's metadata/name is updated.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin implements the plugin.Plugin interface for FIDO2/WebAuthn Passkey authentication.
func New ¶
func New(repo Repository, opts ...Option) *Plugin
New creates and returns a new Passkey plugin configured with the given repository and options.
func (*Plugin) DeletePasskey ¶
func (p *Plugin) DeletePasskey(ctx context.Context, params *DeletePasskeyParams) error
DeletePasskey removes a passkey after verifying caller ownership.
func (*Plugin) GenerateAuthenticationOptions ¶
func (p *Plugin) GenerateAuthenticationOptions(ctx context.Context, params *GenerateAuthenticationOptionsParams) (*AuthenticationOptionsResult, error)
GenerateAuthenticationOptions begins a WebAuthn assertion ceremony for signing in.
func (*Plugin) GenerateRegistrationOptions ¶
func (p *Plugin) GenerateRegistrationOptions(ctx context.Context, params *GenerateRegistrationOptionsParams) (*RegistrationOptionsResult, error)
GenerateRegistrationOptions begins a WebAuthn credential registration ceremony.
func (*Plugin) GetPasskey ¶
GetPasskey retrieves a single passkey by its unique identifier.
func (*Plugin) Init ¶
Init initializes the plugin within the core engine and configures the WebAuthn cryptographic engine.
func (*Plugin) ListPasskeys ¶
func (p *Plugin) ListPasskeys(ctx context.Context, params *ListPasskeysParams) ([]*entity.Passkey, error)
ListPasskeys retrieves all passkeys associated with a user.
func (*Plugin) UpdatePasskey ¶
func (p *Plugin) UpdatePasskey(ctx context.Context, params *UpdatePasskeyParams) (*entity.Passkey, error)
UpdatePasskey modifies a passkey's friendly name after verifying ownership.
func (*Plugin) VerifyAuthentication ¶
func (p *Plugin) VerifyAuthentication(ctx context.Context, params *VerifyAuthenticationParams) (*VerifyAuthenticationResult, error)
VerifyAuthentication verifies a WebAuthn assertion response and issues an authenticated session.
func (*Plugin) VerifyRegistration ¶
func (p *Plugin) VerifyRegistration(ctx context.Context, params *VerifyRegistrationParams) (*entity.Passkey, error)
VerifyRegistration verifies the response from navigator.credentials.create() and registers the passkey.
type RegistrationFailedPayload ¶
type RegistrationFailedPayload struct {
UserID *string `json:"userId,omitempty"`
ChallengeToken string `json:"challengeToken"`
Reason string `json:"reason"`
Extra map[string]any `json:"extra,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
RegistrationFailedPayload is dispatched when registration ceremony verification fails.
type RegistrationOptionsCreatedPayload ¶
type RegistrationOptionsCreatedPayload struct {
UserID string `json:"userId"`
UserName string `json:"userName"`
ChallengeToken string `json:"challengeToken"`
ExpiresAt time.Time `json:"expiresAt"`
Extra map[string]any `json:"extra,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
RegistrationOptionsCreatedPayload is dispatched when a registration challenge is generated.
type RegistrationOptionsResult ¶
type RegistrationOptionsResult struct {
Options *protocol.CredentialCreation `json:"options"`
ChallengeToken string `json:"challengeToken"`
ExpiresAt time.Time `json:"expiresAt"`
}
RegistrationOptionsResult contains creation options sent to the browser and the associated challenge token.
type RegistrationVerifiedPayload ¶
type RegistrationVerifiedPayload struct {
Passkey *entity.Passkey `json:"passkey"`
User *entity.User `json:"user"`
Extra map[string]any `json:"extra,omitempty"`
Timestamp time.Time `json:"timestamp"`
}
RegistrationVerifiedPayload is dispatched when a new passkey credential is authenticated and persisted.
type Repository ¶
type Repository interface {
// Passkeys CRUD
CreatePasskey(ctx context.Context, passkey *entity.Passkey) error
GetPasskeyByID(ctx context.Context, id string) (*entity.Passkey, error)
GetPasskeyByCredentialID(ctx context.Context, credentialID string) (*entity.Passkey, error)
ListPasskeysByUserID(ctx context.Context, userID string) ([]*entity.Passkey, error)
UpdatePasskey(ctx context.Context, passkey *entity.Passkey) error
UpdatePasskeyCounter(ctx context.Context, id string, newCounter uint32) error
DeletePasskey(ctx context.Context, id string) error
DeletePasskeysByUserID(ctx context.Context, userID string) error
// Ephemeral Challenges
SavePasskeyChallenge(ctx context.Context, challenge *PasskeyChallenge) error
GetPasskeyChallenge(ctx context.Context, token string) (*PasskeyChallenge, error)
ConsumePasskeyChallenge(ctx context.Context, token string) (*PasskeyChallenge, error)
DeletePasskeyChallenge(ctx context.Context, token string) error
// User & Session Integration
GetUserByID(ctx context.Context, userID string) (*entity.User, error)
GetUserByEmail(ctx context.Context, email string) (*entity.User, error)
CreateSession(ctx context.Context, session *dto.CreateSessionParams) (*entity.Session, error)
}
Repository defines the storage contract required by the Passkey authentication plugin.
type ResolveUserFunc ¶
type ResolveUserFunc func(ctx context.Context, queryContext *string, extra map[string]any) (*PasskeyRegistrationUser, error)
ResolveUserFunc is invoked to resolve or provision a user identity during registration when requireSession is false.
type UpdatePasskeyParams ¶
type UpdatePasskeyParams struct {
ID string `json:"id"`
CallerUserID string `json:"callerUserId"`
Name string `json:"name"`
}
UpdatePasskeyParams contains update parameters for an existing passkey.
type VerifyAuthenticationParams ¶
type VerifyAuthenticationParams struct {
ChallengeToken string `json:"challengeToken"`
Origin string `json:"origin,omitempty"`
Response *protocol.CredentialAssertionResponse `json:"response"`
Extra map[string]any `json:"extra,omitempty"`
}
VerifyAuthenticationParams holds data returned from navigator.credentials.get() for verification.
type VerifyAuthenticationResult ¶
type VerifyAuthenticationResult struct {
User *entity.User `json:"user"`
Session *entity.Session `json:"session"`
Passkey *entity.Passkey `json:"passkey"`
}
VerifyAuthenticationResult contains authenticated identity, issued session, and the verified passkey.
type VerifyRegistrationParams ¶
type VerifyRegistrationParams struct {
ChallengeToken string `json:"challengeToken"`
Origin string `json:"origin,omitempty"`
Response *protocol.CredentialCreationResponse `json:"response"`
Name *string `json:"name,omitempty"`
CallerUserID *string `json:"callerUserId,omitempty"`
Extra map[string]any `json:"extra,omitempty"`
}
VerifyRegistrationParams holds data returned from navigator.credentials.create() for verification.