passkey

package
v0.19.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
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.

View Source
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.

View Source
const (
	StoreKeyRPID        = "passkey:rp_id"
	StoreKeyRPOrigins   = "passkey:rp_origins"
	StoreKeyRPName      = "passkey:rp_name"
	StoreKeyActiveCount = "passkey:active_count"
)

Shared context storage keys for plugin.Context.

View Source
const AnonymousAAGUID = "00000000-0000-0000-0000-000000000000"

AnonymousAAGUID represents the zero/anonymous AAGUID indicating an unauthenticated or privacy-preserving model.

Variables

View Source
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")
	ErrUnauthorized          = errors.New("passkey: unauthorized to perform this operation")
	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.

View Source
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

func GetAuthenticatorName(aaguid *string) string

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

type DeletePasskeyParams struct {
	ID           string `json:"id"`
	CallerUserID string `json:"callerUserId"`
	plugin.ExtraContainer
}

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.
	plugin.ExtraContainer
}

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"`
	plugin.ExtraContainer
}

GenerateRegistrationOptionsParams holds inputs for creating a WebAuthn credential registration ceremony challenge.

type ListPasskeysParams

type ListPasskeysParams struct {
	UserID string `json:"userId"`
	plugin.ExtraContainer
}

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

func WithChallengeTimeout(d time.Duration) Option

WithChallengeTimeout sets the validity duration for ephemeral challenges.

func WithRPDisplayName

func WithRPDisplayName(name string) Option

WithRPDisplayName sets the Relying Party human-readable name.

func WithRPID

func WithRPID(rpID string) Option

WithRPID sets the Relying Party domain identifier (e.g. "auth.example.com" or "localhost").

func WithRPOrigins

func WithRPOrigins(origins ...string) Option

WithRPOrigins sets the list of allowed origin URLs.

func WithRequireSessionOnRegistration

func WithRequireSessionOnRegistration(require bool) Option

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

func WithSessionDuration(d time.Duration) Option

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) Config

func (p *Plugin) Config() Config

Config returns a copy of the current configuration.

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

func (p *Plugin) GetPasskey(ctx context.Context, id string) (*entity.Passkey, error)

GetPasskey retrieves a single passkey by its unique identifier.

func (*Plugin) ID

func (p *Plugin) ID() string

ID returns the unique identifier for the Passkey plugin.

func (*Plugin) Init

func (p *Plugin) Init(ctx *plugin.Context) error

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"`
	plugin.ExtraContainer
}

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"`
	plugin.ExtraContainer
}

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"`
	plugin.ExtraContainer
}

VerifyRegistrationParams holds data returned from navigator.credentials.create() for verification.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL