Documentation
¶
Overview ¶
Package passkeys owns the per-user WebAuthn surface: registering, listing, renaming, and deleting the caller's own passkeys, plus setting and removing the caller's password. It also drives the public login ceremony (begin / finish), which has no principal yet.
Ceremony challenge state lives in the webauthn_ceremonies table (short-lived, single-use) so a multi-replica deployment can finish a ceremony on a different instance than began it. Every credential a user owns is one row in webauthn_credentials; the raw public key never leaves the backend.
Index ¶
- Variables
- type LoginResult
- type Passkey
- type Service
- func (s *Service) Delete(ctx context.Context, p authz.Principal, id uuid.UUID) error
- func (s *Service) GC(ctx context.Context) error
- func (s *Service) List(ctx context.Context, p authz.Principal) ([]Passkey, error)
- func (s *Service) LoginBegin(ctx context.Context, _ string) (ceremonyID string, options *protocol.CredentialAssertion, err error)
- func (s *Service) LoginFinish(ctx context.Context, ceremonyID string, r *http.Request) (LoginResult, error)
- func (s *Service) RegisterBegin(ctx context.Context, p authz.Principal) (ceremonyID string, options *protocol.CredentialCreation, err error)
- func (s *Service) RegisterFinish(ctx context.Context, p authz.Principal, ceremonyID, friendlyName string, ...) (Passkey, error)
- func (s *Service) RemovePassword(ctx context.Context, p authz.Principal) error
- func (s *Service) Rename(ctx context.Context, p authz.Principal, id uuid.UUID, name string) error
- func (s *Service) SetPassword(ctx context.Context, p authz.Principal, password string) error
Constants ¶
This section is empty.
Variables ¶
var ErrNeedsReauth = errors.New("passkey assertion failed")
ErrNeedsReauth is returned by the login finish path when the assertion is invalid — the handler maps it to 401.
Functions ¶
This section is empty.
Types ¶
type LoginResult ¶
type LoginResult struct {
UserID uuid.UUID
Email string
DisplayName string
TenantRole string
MustChangePassword bool
}
LoginResult carries the identity a successful assertion resolved to, enough for the handler to mint tokens without re-reading the row.
type Passkey ¶
type Passkey struct {
ID uuid.UUID
FriendlyName string
CreatedAt pgtype.Timestamptz
LastUsedAt pgtype.Timestamptz
BackupEligible bool
}
Passkey is the wire shape the handler sees — display metadata only, never the public key or raw credential id.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is the per-user passkey + password layer. Authenticated methods gate on TenantSelfPasskeyManage (any user manages their own); the login ceremony is public.
func (*Service) Delete ¶
Delete removes one of the caller's passkeys, refusing to remove the last sign-in credential (a user with no passkey and no password could never log in again).
func (*Service) LoginBegin ¶
func (s *Service) LoginBegin(ctx context.Context, _ string) (ceremonyID string, options *protocol.CredentialAssertion, err error)
LoginBegin starts a usernameless ceremony. Login options are always discoverable so neither the response nor the authenticator credential list reveals whether a submitted email exists or has passkeys.
func (*Service) LoginFinish ¶
func (s *Service) LoginFinish(ctx context.Context, ceremonyID string, r *http.Request) (LoginResult, error)
LoginFinish completes a login ceremony and returns the resolved identity. The assertion is read from r.Body by go-webauthn. On success the matched credential's sign counter is advanced.
func (*Service) RegisterBegin ¶
func (s *Service) RegisterBegin(ctx context.Context, p authz.Principal) (ceremonyID string, options *protocol.CredentialCreation, err error)
RegisterBegin starts a registration ceremony for the caller. The returned options are handed to the browser; ceremonyID must be echoed to RegisterFinish.
func (*Service) RegisterFinish ¶
func (s *Service) RegisterFinish(ctx context.Context, p authz.Principal, ceremonyID, friendlyName string, r *http.Request) (Passkey, error)
RegisterFinish completes a registration ceremony. The attestation is read straight from r.Body by go-webauthn; ceremonyID and friendlyName come from the query string. Registering a passkey also clears must_change_password — it satisfies the "secure your account" requirement.
func (*Service) RemovePassword ¶
RemovePassword clears the caller's password, refusing if it would leave no sign-in credential (no passkey registered).