Documentation
¶
Overview ¶
Package passkey provides WebAuthn/FIDO2 passkey authentication.
✅ PRODUCTION READY ✅
This plugin provides enterprise-grade WebAuthn/FIDO2 authentication with: - Full cryptographic challenge generation and verification - Attestation verification during registration - Signature verification during authentication - Sign count tracking for replay attack prevention - Resident key / discoverable credential support - App and organization scoping for multi-tenancy - Both standalone passwordless and MFA integration modes
See plugins/passkey/README.md for complete documentation and usage examples.
Index ¶
- func ParseAuthenticatorAttachment(s string) protocol.AuthenticatorAttachment
- func ParseConveyancePreference(s string) protocol.ConveyancePreference
- func ParseResidentKeyRequirement(required bool) protocol.ResidentKeyRequirement
- func ParseUserVerificationRequirement(s string) protocol.UserVerificationRequirement
- type BeginLoginRequest
- type BeginLoginResponse
- type BeginRegisterRequest
- type BeginRegisterResponse
- type ChallengeSession
- type ChallengeStore
- type Config
- type DeletePasskeyRequest
- type ErrorResponse
- type FinishLoginRequest
- type FinishRegisterRequest
- type FinishRegisterResponse
- type GetPasskeyRequest
- type Handler
- func (h *Handler) BeginLogin(c forge.Context) error
- func (h *Handler) BeginRegister(c forge.Context) error
- func (h *Handler) Delete(c forge.Context) error
- func (h *Handler) FinishLogin(c forge.Context) error
- func (h *Handler) FinishRegister(c forge.Context) error
- func (h *Handler) Get(c forge.Context) error
- func (h *Handler) List(c forge.Context) error
- func (h *Handler) Update(c forge.Context) error
- type ListPasskeysRequest
- type ListPasskeysResponse
- type LoginResponse
- type MemoryChallengeStore
- func (s *MemoryChallengeStore) CleanupExpired(ctx context.Context) error
- func (s *MemoryChallengeStore) Delete(ctx context.Context, sessionID string) error
- func (s *MemoryChallengeStore) Get(ctx context.Context, sessionID string) (*ChallengeSession, error)
- func (s *MemoryChallengeStore) Store(ctx context.Context, sessionID string, session *ChallengeSession) error
- type MessageResponse
- type PasskeyErrorResponse
- type PasskeyInfo
- type PasskeyListResponse
- type PasskeyLoginOptionsResponse
- type PasskeyLoginResponse
- type PasskeyRegistrationOptionsResponse
- type PasskeyStatusResponse
- type Plugin
- func (p *Plugin) ID() string
- func (p *Plugin) Init(authInst core.Authsome) error
- func (p *Plugin) Migrate() error
- func (p *Plugin) RegisterHooks(_ *hooks.HookRegistry) error
- func (p *Plugin) RegisterRoutes(router forge.Router) error
- func (p *Plugin) RegisterServiceDecorators(_ *registry.ServiceRegistry) error
- type PluginOption
- func WithAttestationType(attestation string) PluginOption
- func WithAuthenticatorAttachment(attachment string) PluginOption
- func WithChallengeStorage(storage string) PluginOption
- func WithDefaultConfig(cfg Config) PluginOption
- func WithRPID(rpID string) PluginOption
- func WithRPName(rpName string) PluginOption
- func WithRPOrigins(origins []string) PluginOption
- func WithRequireResidentKey(required bool) PluginOption
- func WithTimeout(timeout time.Duration) PluginOption
- func WithUserVerification(requirement string) PluginOption
- type RedisChallengeStore
- type Service
- func (s *Service) BeginDiscoverableLogin(ctx context.Context, req BeginLoginRequest) (*BeginLoginResponse, error)
- func (s *Service) BeginLogin(ctx context.Context, userID xid.ID, req BeginLoginRequest) (*BeginLoginResponse, error)
- func (s *Service) BeginRegistration(ctx context.Context, userID xid.ID, req BeginRegisterRequest) (*BeginRegisterResponse, error)
- func (s *Service) Delete(ctx context.Context, passkeyID xid.ID, ip, ua string) error
- func (s *Service) FinishLogin(ctx context.Context, credentialResponse []byte, remember bool, ip, ua string) (*LoginResponse, error)
- func (s *Service) FinishRegistration(ctx context.Context, userID xid.ID, credentialResponse []byte, ...) (*FinishRegisterResponse, error)
- func (s *Service) List(ctx context.Context, userID xid.ID) (*ListPasskeysResponse, error)
- func (s *Service) Update(ctx context.Context, passkeyID xid.ID, name string) (*UpdatePasskeyResponse, error)
- type StatusResponse
- type UpdatePasskeyRequest
- type UpdatePasskeyResponse
- type UserAdapter
- func (u *UserAdapter) AddCredential(cred webauthn.Credential)
- func (u *UserAdapter) UpdateCredential(credentialID []byte, signCount uint32)
- func (u *UserAdapter) WebAuthnCredentials() []webauthn.Credential
- func (u *UserAdapter) WebAuthnDisplayName() string
- func (u *UserAdapter) WebAuthnID() []byte
- func (u *UserAdapter) WebAuthnIcon() string
- func (u *UserAdapter) WebAuthnName() string
- type WebAuthnWrapper
- func (w *WebAuthnWrapper) BeginDiscoverableLogin(opts ...webauthn.LoginOption) (*protocol.CredentialAssertion, *webauthn.SessionData, error)
- func (w *WebAuthnWrapper) BeginLogin(user webauthn.User, opts ...webauthn.LoginOption) (*protocol.CredentialAssertion, *webauthn.SessionData, error)
- func (w *WebAuthnWrapper) BeginRegistration(user webauthn.User, opts ...webauthn.RegistrationOption) (*protocol.CredentialCreation, *webauthn.SessionData, error)
- func (w *WebAuthnWrapper) FinishLogin(user webauthn.User, session webauthn.SessionData, ...) (*webauthn.Credential, error)
- func (w *WebAuthnWrapper) FinishRegistration(user webauthn.User, session webauthn.SessionData, ...) (*webauthn.Credential, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ParseAuthenticatorAttachment ¶
func ParseAuthenticatorAttachment(s string) protocol.AuthenticatorAttachment
ParseAuthenticatorAttachment converts string to protocol type
func ParseConveyancePreference ¶
func ParseConveyancePreference(s string) protocol.ConveyancePreference
ParseConveyancePreference converts string to protocol type
func ParseResidentKeyRequirement ¶
func ParseResidentKeyRequirement(required bool) protocol.ResidentKeyRequirement
ParseResidentKeyRequirement converts bool to protocol type
func ParseUserVerificationRequirement ¶
func ParseUserVerificationRequirement(s string) protocol.UserVerificationRequirement
ParseUserVerificationRequirement converts string to protocol type
Types ¶
type BeginLoginRequest ¶
type BeginLoginRequest struct {
UserID string `json:"userId,omitempty" validate:"omitempty,xid"` // Optional for discoverable credentials
UserVerification string `json:"userVerification,omitempty" validate:"omitempty,oneof=required preferred discouraged"`
}
BeginLoginRequest initiates passkey authentication
type BeginLoginResponse ¶
type BeginLoginResponse struct {
Options interface{} `json:"options"` // WebAuthn PublicKeyCredentialRequestOptions
Challenge string `json:"challenge"` // Base64URL encoded challenge
Timeout time.Duration `json:"timeout"` // Timeout in milliseconds
}
BeginLoginResponse contains WebAuthn authentication options
type BeginRegisterRequest ¶
type BeginRegisterRequest struct {
UserID string `json:"userId" validate:"required,xid"`
Name string `json:"name,omitempty" validate:"omitempty,min=1,max=100"`
AuthenticatorType string `json:"authenticatorType,omitempty" validate:"omitempty,oneof=platform cross-platform"`
RequireResidentKey bool `json:"requireResidentKey"`
UserVerification string `json:"userVerification,omitempty" validate:"omitempty,oneof=required preferred discouraged"`
}
BeginRegisterRequest initiates passkey registration
type BeginRegisterResponse ¶
type BeginRegisterResponse struct {
Options interface{} `json:"options"` // WebAuthn PublicKeyCredentialCreationOptions
Challenge string `json:"challenge"` // Base64URL encoded challenge
UserID string `json:"userId"`
Timeout time.Duration `json:"timeout"` // Timeout in milliseconds
}
BeginRegisterResponse contains WebAuthn registration options
type ChallengeSession ¶
type ChallengeSession struct {
Challenge []byte
UserID xid.ID
SessionData interface{} // webauthn.SessionData
CreatedAt time.Time
ExpiresAt time.Time
}
ChallengeSession stores WebAuthn challenge data with timeout
type ChallengeStore ¶
type ChallengeStore interface {
// Store saves a challenge session with expiration
Store(ctx context.Context, sessionID string, session *ChallengeSession) error
// Get retrieves a challenge session
Get(ctx context.Context, sessionID string) (*ChallengeSession, error)
// Delete removes a challenge session
Delete(ctx context.Context, sessionID string) error
// CleanupExpired removes all expired challenge sessions
CleanupExpired(ctx context.Context) error
}
ChallengeStore defines the interface for challenge session storage
type Config ¶
type Config struct {
RPID string `json:"rpid" yaml:"rpid"`
RPName string `json:"rpname" yaml:"rpname"`
RPOrigins []string `json:"rporigins" yaml:"rporigins"`
Timeout time.Duration `json:"timeout" yaml:"timeout"` // milliseconds
UserVerification string `json:"userverification" yaml:"userverification"` // required, preferred, discouraged
AttestationType string `json:"attestationtype" yaml:"attestationtype"` // none, indirect, direct
RequireResidentKey bool `json:"requireresidentkey" yaml:"requireresidentkey"` // require resident keys
AuthenticatorAttachment string `json:"authenticatorattachment" yaml:"authenticatorattachment"` // platform, cross-platform, or empty
ChallengeStorage string `json:"challengestorage" yaml:"challengestorage"` // memory or redis (future)
}
Config contains WebAuthn/FIDO2 configuration
type DeletePasskeyRequest ¶
type DeletePasskeyRequest struct {
ID string `path:"id" validate:"required,xid"`
}
DeletePasskeyRequest deletes a passkey
type ErrorResponse ¶
type ErrorResponse = responses.ErrorResponse
Response types - use shared responses from core
type FinishLoginRequest ¶
type FinishLoginRequest struct {
Response map[string]interface{} `json:"response" validate:"required"` // WebAuthn PublicKeyCredential assertion
Remember bool `json:"remember"`
}
FinishLoginRequest completes passkey authentication
type FinishRegisterRequest ¶
type FinishRegisterRequest struct {
UserID string `json:"userId" validate:"required,xid"`
Name string `json:"name,omitempty" validate:"omitempty,min=1,max=100"`
Response map[string]interface{} `json:"response" validate:"required"` // WebAuthn PublicKeyCredential
}
FinishRegisterRequest completes passkey registration with credential attestation
type FinishRegisterResponse ¶
type FinishRegisterResponse struct {
PasskeyID string `json:"passkeyId"`
Name string `json:"name"`
Status string `json:"status"`
CreatedAt time.Time `json:"createdAt"`
CredentialID string `json:"credentialId"`
}
FinishRegisterResponse contains registered passkey information
type GetPasskeyRequest ¶
type GetPasskeyRequest struct {
ID string `path:"id" validate:"required,xid"`
}
GetPasskeyRequest retrieves a single passkey
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
func NewHandler ¶
func (*Handler) BeginLogin ¶
BeginLogin initiates passkey authentication with WebAuthn challenge
func (*Handler) BeginRegister ¶
BeginRegister initiates passkey registration with WebAuthn challenge
func (*Handler) FinishLogin ¶
FinishLogin completes passkey authentication with signature verification
func (*Handler) FinishRegister ¶
FinishRegister completes passkey registration with attestation verification
type ListPasskeysRequest ¶
type ListPasskeysRequest struct {
UserID string `query:"userId" validate:"required,xid"`
}
ListPasskeysRequest retrieves user's passkeys
type ListPasskeysResponse ¶
type ListPasskeysResponse struct {
Passkeys []PasskeyInfo `json:"passkeys"`
Count int `json:"count"`
}
ListPasskeysResponse contains list of user passkeys
type LoginResponse ¶
type LoginResponse struct {
User interface{} `json:"user"`
Session interface{} `json:"session"`
Token string `json:"token"`
PasskeyUsed string `json:"passkeyUsed"` // ID of the passkey that was used
}
LoginResponse contains authentication result with session
type MemoryChallengeStore ¶
type MemoryChallengeStore struct {
// contains filtered or unexported fields
}
MemoryChallengeStore is an in-memory implementation of ChallengeStore For production with multiple instances, use RedisChallengeStore instead
func NewMemoryChallengeStore ¶
func NewMemoryChallengeStore(timeout time.Duration) *MemoryChallengeStore
NewMemoryChallengeStore creates a new in-memory challenge store
func (*MemoryChallengeStore) CleanupExpired ¶
func (s *MemoryChallengeStore) CleanupExpired(ctx context.Context) error
CleanupExpired removes all expired sessions
func (*MemoryChallengeStore) Delete ¶
func (s *MemoryChallengeStore) Delete(ctx context.Context, sessionID string) error
Delete removes a challenge session
func (*MemoryChallengeStore) Get ¶
func (s *MemoryChallengeStore) Get(ctx context.Context, sessionID string) (*ChallengeSession, error)
Get retrieves a challenge session
func (*MemoryChallengeStore) Store ¶
func (s *MemoryChallengeStore) Store(ctx context.Context, sessionID string, session *ChallengeSession) error
Store saves a challenge session
type MessageResponse ¶
type MessageResponse = responses.MessageResponse
type PasskeyErrorResponse ¶
type PasskeyErrorResponse = ErrorResponse
Legacy response type aliases for backward compatibility Use the proper types defined in response_types.go instead
type PasskeyInfo ¶
type PasskeyInfo struct {
ID string `json:"id"`
Name string `json:"name"`
CredentialID string `json:"credentialId"`
AAGUID string `json:"aaguid,omitempty"`
AuthenticatorType string `json:"authenticatorType"` // "platform" or "cross-platform"
CreatedAt time.Time `json:"createdAt"`
LastUsedAt *time.Time `json:"lastUsedAt,omitempty"`
SignCount uint32 `json:"signCount"`
IsResidentKey bool `json:"isResidentKey"`
}
PasskeyInfo represents detailed passkey information
type PasskeyListResponse ¶
type PasskeyListResponse = ListPasskeysResponse
type PasskeyLoginOptionsResponse ¶
type PasskeyLoginOptionsResponse = BeginLoginResponse
type PasskeyLoginResponse ¶
type PasskeyLoginResponse = LoginResponse
type PasskeyRegistrationOptionsResponse ¶
type PasskeyRegistrationOptionsResponse = BeginRegisterResponse
type PasskeyStatusResponse ¶
type PasskeyStatusResponse = StatusResponse
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
func NewPlugin ¶
func NewPlugin(opts ...PluginOption) *Plugin
NewPlugin creates a new passkey plugin instance with optional configuration
func (*Plugin) RegisterHooks ¶
func (p *Plugin) RegisterHooks(_ *hooks.HookRegistry) error
func (*Plugin) RegisterServiceDecorators ¶
func (p *Plugin) RegisterServiceDecorators(_ *registry.ServiceRegistry) error
type PluginOption ¶
type PluginOption func(*Plugin)
PluginOption is a functional option for configuring the passkey plugin
func WithAttestationType ¶
func WithAttestationType(attestation string) PluginOption
WithAttestationType sets the attestation conveyance preference
func WithAuthenticatorAttachment ¶
func WithAuthenticatorAttachment(attachment string) PluginOption
WithAuthenticatorAttachment sets the authenticator attachment preference
func WithChallengeStorage ¶
func WithChallengeStorage(storage string) PluginOption
WithChallengeStorage sets the challenge storage backend
func WithDefaultConfig ¶
func WithDefaultConfig(cfg Config) PluginOption
WithDefaultConfig sets the default configuration for the plugin
func WithRPName ¶
func WithRPName(rpName string) PluginOption
WithRPName sets the Relying Party Name
func WithRPOrigins ¶
func WithRPOrigins(origins []string) PluginOption
WithRPOrigins sets the allowed origins for WebAuthn
func WithRequireResidentKey ¶
func WithRequireResidentKey(required bool) PluginOption
WithRequireResidentKey sets whether resident keys are required
func WithTimeout ¶
func WithTimeout(timeout time.Duration) PluginOption
WithTimeout sets the WebAuthn timeout
func WithUserVerification ¶
func WithUserVerification(requirement string) PluginOption
WithUserVerification sets the user verification requirement
type RedisChallengeStore ¶
type RedisChallengeStore struct {
}
RedisChallengeStore is a Redis-backed implementation of ChallengeStore This is recommended for production environments with multiple instances
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service provides passkey/WebAuthn operations with full cryptographic verification
func NewService ¶
func NewService(db *bun.DB, userSvc *user.Service, authSvc *auth.Service, auditSvc *audit.Service, cfg Config) (*Service, error)
NewService creates a new passkey service with WebAuthn support
func (*Service) BeginDiscoverableLogin ¶
func (s *Service) BeginDiscoverableLogin(ctx context.Context, req BeginLoginRequest) (*BeginLoginResponse, error)
BeginDiscoverableLogin initiates authentication for discoverable credentials (usernameless)
func (*Service) BeginLogin ¶
func (s *Service) BeginLogin(ctx context.Context, userID xid.ID, req BeginLoginRequest) (*BeginLoginResponse, error)
BeginLogin initiates WebAuthn authentication challenge
func (*Service) BeginRegistration ¶
func (s *Service) BeginRegistration(ctx context.Context, userID xid.ID, req BeginRegisterRequest) (*BeginRegisterResponse, error)
BeginRegistration initiates WebAuthn passkey registration with cryptographic challenge
func (*Service) FinishLogin ¶
func (s *Service) FinishLogin(ctx context.Context, credentialResponse []byte, remember bool, ip, ua string) (*LoginResponse, error)
FinishLogin completes authentication with signature verification and creates session
func (*Service) FinishRegistration ¶
func (s *Service) FinishRegistration(ctx context.Context, userID xid.ID, credentialResponse []byte, name, ip, ua string) (*FinishRegisterResponse, error)
FinishRegistration completes passkey registration with attestation verification
type StatusResponse ¶
type StatusResponse = responses.StatusResponse
type UpdatePasskeyRequest ¶
type UpdatePasskeyRequest struct {
ID string `path:"id" validate:"required,xid"`
Name string `json:"name" validate:"required,min=1,max=100"`
}
UpdatePasskeyRequest updates passkey metadata (name)
type UpdatePasskeyResponse ¶
type UpdatePasskeyResponse struct {
PasskeyID string `json:"passkeyId"`
Name string `json:"name"`
UpdatedAt time.Time `json:"updatedAt"`
}
UpdatePasskeyResponse contains updated passkey information
type UserAdapter ¶
type UserAdapter struct {
// contains filtered or unexported fields
}
UserAdapter adapts AuthSome User to WebAuthn User interface
func NewUserAdapter ¶
func NewUserAdapter(userID xid.ID, userName, displayName string, passkeys []schema.Passkey) *UserAdapter
NewUserAdapter creates a new user adapter for WebAuthn
func (*UserAdapter) AddCredential ¶
func (u *UserAdapter) AddCredential(cred webauthn.Credential)
AddCredential adds a new credential to the user adapter
func (*UserAdapter) UpdateCredential ¶
func (u *UserAdapter) UpdateCredential(credentialID []byte, signCount uint32)
UpdateCredential updates an existing credential's sign count
func (*UserAdapter) WebAuthnCredentials ¶
func (u *UserAdapter) WebAuthnCredentials() []webauthn.Credential
WebAuthnCredentials returns the user's credentials
func (*UserAdapter) WebAuthnDisplayName ¶
func (u *UserAdapter) WebAuthnDisplayName() string
WebAuthnDisplayName returns the user's display name
func (*UserAdapter) WebAuthnID ¶
func (u *UserAdapter) WebAuthnID() []byte
WebAuthnID returns the user's ID as bytes
func (*UserAdapter) WebAuthnIcon ¶
func (u *UserAdapter) WebAuthnIcon() string
WebAuthnIcon returns the user's icon URL (optional)
func (*UserAdapter) WebAuthnName ¶
func (u *UserAdapter) WebAuthnName() string
WebAuthnName returns the user's username
type WebAuthnWrapper ¶
type WebAuthnWrapper struct {
// contains filtered or unexported fields
}
WebAuthnWrapper wraps the go-webauthn/webauthn library for easier use
func NewWebAuthnWrapper ¶
func NewWebAuthnWrapper(cfg Config) (*WebAuthnWrapper, error)
NewWebAuthnWrapper creates a new WebAuthn wrapper with configuration
func (*WebAuthnWrapper) BeginDiscoverableLogin ¶
func (w *WebAuthnWrapper) BeginDiscoverableLogin(opts ...webauthn.LoginOption) (*protocol.CredentialAssertion, *webauthn.SessionData, error)
BeginDiscoverableLogin initiates authentication for discoverable credentials (usernameless)
func (*WebAuthnWrapper) BeginLogin ¶
func (w *WebAuthnWrapper) BeginLogin(user webauthn.User, opts ...webauthn.LoginOption) (*protocol.CredentialAssertion, *webauthn.SessionData, error)
BeginLogin initiates WebAuthn authentication
func (*WebAuthnWrapper) BeginRegistration ¶
func (w *WebAuthnWrapper) BeginRegistration(user webauthn.User, opts ...webauthn.RegistrationOption) (*protocol.CredentialCreation, *webauthn.SessionData, error)
BeginRegistration initiates WebAuthn credential registration
func (*WebAuthnWrapper) FinishLogin ¶
func (w *WebAuthnWrapper) FinishLogin(user webauthn.User, session webauthn.SessionData, response *protocol.ParsedCredentialAssertionData) (*webauthn.Credential, error)
FinishLogin completes WebAuthn authentication with credential verification
func (*WebAuthnWrapper) FinishRegistration ¶
func (w *WebAuthnWrapper) FinishRegistration(user webauthn.User, session webauthn.SessionData, response *protocol.ParsedCredentialCreationData) (*webauthn.Credential, error)
FinishRegistration completes WebAuthn credential registration