passkeyauth

package
v0.9.21 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Overview

Package passkeyauth provides application-neutral WebAuthn authentication primitives for first-party term-llm servers. It owns relying-party protocol handling, a versioned single-user credential store, browser sessions, ceremonies, and host-controlled enrollment grants.

Callers supply product policy such as the public endpoint, relying-party and user display names, store location, HTTP routes, cookie names, and UI. The package deliberately contains no Hub routing, branding, or proxy behavior so serve variants can share one authentication engine.

Index

Constants

View Source
const (
	HostGrantLifetime    = 10 * time.Minute
	GrantSessionLifetime = 5 * time.Minute
	CeremonyLifetime     = 5 * time.Minute
	MaxGrantSessions     = 8
	MaxCeremonies        = 512
	MaxCeremoniesPerPeer = 16
)
View Source
const (
	StoreVersion          = 1
	DefaultUserName       = "Passkey user"
	DefaultCredentialName = "Primary passkey"
)
View Source
const (
	SessionIdleLifetime          = 12 * time.Hour
	SessionAbsoluteLifetime      = 7 * 24 * time.Hour
	SessionActivityWriteInterval = 5 * time.Minute
	RecentAuthLifetime           = 5 * time.Minute
	MaxSessions                  = 1024
)

Variables

View Source
var (
	ErrInvalidGrant    = errors.New("invalid or expired host grant")
	ErrGrantConsumed   = errors.New("host grant already consumed")
	ErrCapacity        = errors.New("authentication capacity reached")
	ErrInvalidCeremony = errors.New("invalid or expired ceremony")
)
View Source
var (
	ErrInvalidSession     = errors.New("invalid or expired session")
	ErrSessionCapacity    = errors.New("session capacity reached")
	ErrRecentAuthRequired = errors.New("recent authentication required")
)
View Source
var (
	ErrFirstCredentialExists = errors.New("first credential already exists")
	ErrDuplicateCredential   = errors.New("credential is already enrolled")
	ErrCredentialNotFound    = errors.New("credential not found")
	ErrFinalCredential       = errors.New("cannot remove the final credential")
)

Functions

func GenerateBootstrapSecret

func GenerateBootstrapSecret(r io.Reader) ([]byte, string, error)

func NormalizeCredentialName

func NormalizeCredentialName(name string) (string, error)

func ReadPrivateSecretFile

func ReadPrivateSecretFile(path string) ([]byte, error)

ReadPrivateSecretFile reads an operator-managed bootstrap/recovery secret without following symlinks or accepting broadly accessible Unix files.

func ValidateHostSecret

func ValidateHostSecret(secret []byte) error

Types

type Ceremonies

type Ceremonies struct {
	// contains filtered or unexported fields
}

func NewCeremonies

func NewCeremonies(now func() time.Time, random io.Reader) *Ceremonies

func (*Ceremonies) Consume

func (c *Ceremonies) Consume(token string, kind CeremonyKind, grantID, sessionID string) (Ceremony, error)

func (*Ceremonies) Create

func (c *Ceremonies) Create(kind CeremonyKind, peer, grantID, sessionID, meta string, userHandle []byte, data webauthn.SessionData) (Ceremony, error)

type Ceremony

type Ceremony struct {
	ID, CookieToken, Peer    string
	Kind                     CeremonyKind
	GrantID, SessionID, Meta string
	UserHandle               []byte
	Data                     webauthn.SessionData
	ExpiresAt                time.Time
}

type CeremonyKind

type CeremonyKind string
const (
	CeremonyLogin         CeremonyKind = "login"
	CeremonyReauth        CeremonyKind = "reauth"
	CeremonyBootstrap     CeremonyKind = "bootstrap"
	CeremonyRecovery      CeremonyKind = "recovery"
	CeremonyAddCredential CeremonyKind = "add_credential"
)

type Credential

type Credential struct {
	RecordID    string              `json:"-"`
	DisplayName string              `json:"-"`
	WebAuthn    webauthn.Credential `json:"-"`
	CreatedAt   time.Time           `json:"-"`
	LastUsedAt  time.Time           `json:"-"`
}

Credential wraps protocol state in an application-owned, versioned on-disk representation. WebAuthn is deliberately excluded from default JSON encoding; MarshalJSON and UnmarshalJSON below enumerate every persisted protocol field.

func (Credential) MarshalJSON

func (c Credential) MarshalJSON() ([]byte, error)

func (*Credential) UnmarshalJSON

func (c *Credential) UnmarshalJSON(data []byte) error

type Endpoint

type Endpoint struct {
	URL        *url.URL
	Origin     string
	RPID       string
	BasePath   string
	CookiePath string
	Secure     bool
}

Endpoint is the browser-visible WebAuthn relying-party configuration.

func ParseEndpoint

func ParseEndpoint(opts EndpointOptions) (Endpoint, error)

ParseEndpoint validates a browser-visible URL without consulting request-controlled Host or forwarding headers.

func (Endpoint) SafeReturnPath

func (e Endpoint) SafeReturnPath(raw string) string

SafeReturnPath accepts only a root-relative browser path beneath the configured mount.

type EndpointOptions

type EndpointOptions struct {
	PublicURL        string
	BasePath         string
	BasePathExplicit bool
}

type GrantKind

type GrantKind string
const (
	GrantBootstrap GrantKind = "bootstrap"
	GrantRecovery  GrantKind = "recovery"
)

type GrantSession

type GrantSession struct {
	ID, Token string
	Kind      GrantKind
	ExpiresAt time.Time
}

type Grants

type Grants struct {
	// contains filtered or unexported fields
}

func NewGrants

func NewGrants(kind GrantKind, secret []byte, now func() time.Time, random io.Reader) (*Grants, error)

func (*Grants) Authenticate

func (g *Grants) Authenticate(token string) (string, error)

func (*Grants) Consume

func (g *Grants) Consume(token string) error

func (*Grants) Enabled

func (g *Grants) Enabled() bool

func (*Grants) Verify

func (g *Grants) Verify(secret []byte) (GrantSession, error)

type IssuedSession

type IssuedSession struct {
	Token string
	Info  SessionInfo
}

type Principal

type Principal struct{ SessionID, CredentialRecordID string }

type RelyingParty

type RelyingParty struct {
	// contains filtered or unexported fields
}

RelyingParty pins WebAuthn validation to the configured public origin and RP ID.

func NewRelyingParty

func NewRelyingParty(opts RelyingPartyOptions) (*RelyingParty, error)

func (*RelyingParty) BeginLogin

func (*RelyingParty) BeginRegistration

func (r *RelyingParty) BeginRegistration(user User) (*protocol.CredentialCreation, webauthn.SessionData, error)

func (*RelyingParty) FinishLogin

func (r *RelyingParty) FinishLogin(user User, session webauthn.SessionData, request *http.Request) (webauthn.Credential, error)

func (*RelyingParty) FinishRegistration

func (r *RelyingParty) FinishRegistration(user User, session webauthn.SessionData, request *http.Request) (webauthn.Credential, error)

type RelyingPartyOptions

type RelyingPartyOptions struct {
	Endpoint    Endpoint
	DisplayName string
}

RelyingPartyOptions contains application policy needed to construct a WebAuthn relying party. Endpoint validation remains independent so callers can share it with cookie and request-origin handling.

type SessionInfo

type SessionInfo struct {
	ID                 string    `json:"-"`
	CredentialRecordID string    `json:"-"`
	CreatedAt          time.Time `json:"created_at"`
	LastSeenAt         time.Time `json:"last_seen_at"`
	IdleExpiresAt      time.Time `json:"idle_expires_at"`
	AbsoluteExpiresAt  time.Time `json:"absolute_expires_at"`
}

type Sessions

type Sessions struct {
	// contains filtered or unexported fields
}

func NewSessions

func NewSessions(now func() time.Time, random io.Reader) *Sessions

NewSessions returns an in-memory session registry. Hub runtimes should use OpenSessions so authenticated browser sessions survive process restarts.

func OpenSessions added in v0.9.0

func OpenSessions(opts SessionsOptions) (*Sessions, error)

OpenSessions opens or creates a private durable session registry. Only token hashes are persisted; raw browser cookie tokens remain known only to clients.

func (*Sessions) Authenticate

func (s *Sessions) Authenticate(token string) (Principal, error)

func (*Sessions) Close added in v0.9.0

func (s *Sessions) Close() error

func (*Sessions) ConsumeRecentAuth

func (s *Sessions) ConsumeRecentAuth(p Principal) error

func (*Sessions) Count

func (s *Sessions) Count() int

func (*Sessions) Create

func (s *Sessions) Create(credentialRecordID string) (IssuedSession, error)

func (*Sessions) GrantRecentAuth

func (s *Sessions) GrantRecentAuth(p Principal) error

func (*Sessions) HasRecentAuth

func (s *Sessions) HasRecentAuth(p Principal) bool

func (*Sessions) Info

func (s *Sessions) Info(p Principal) (SessionInfo, error)

func (*Sessions) Logout

func (s *Sessions) Logout(p Principal) error

func (*Sessions) RevokeCredential

func (s *Sessions) RevokeCredential(recordID string) (int, error)

func (*Sessions) RevokeOthers

func (s *Sessions) RevokeOthers(p Principal) (int, error)

type SessionsOptions added in v0.9.0

type SessionsOptions struct {
	Path            string
	RPID            string
	UserID          string
	Now             func() time.Time
	Random          io.Reader
	ValidCredential func(string) bool
	Warnf           func(string, ...any)
	WriteFile       func(string, []byte, os.FileMode) error
}

type Store

type Store struct {
	// contains filtered or unexported fields
}

func OpenStore

func OpenStore(opts StoreOptions) (*Store, error)

func (*Store) AddCredential

func (s *Store) AddCredential(raw webauthn.Credential, name string) (Credential, error)

func (*Store) CommitFirstCredential

func (s *Store) CommitFirstCredential(raw webauthn.Credential, name string) (Credential, error)

func (*Store) CredentialCount

func (s *Store) CredentialCount() int

func (*Store) Credentials

func (s *Store) Credentials() []Credential

func (*Store) DeleteCredential

func (s *Store) DeleteCredential(recordID string) (Credential, error)

func (*Store) HasCredential added in v0.9.0

func (s *Store) HasCredential(recordID string) bool

func (*Store) Path

func (s *Store) Path() string

func (*Store) RenameCredential

func (s *Store) RenameCredential(recordID, name string) (Credential, error)

func (*Store) UpdateAfterAssertion

func (s *Store) UpdateAfterAssertion(validated webauthn.Credential, reportedSignCount ...uint32) (Credential, error)

func (*Store) User

func (s *Store) User() User

type StoreOptions

type StoreOptions struct {
	Path      string
	RPID      string
	UserName  string
	Now       func() time.Time
	Random    io.Reader
	Warnf     func(string, ...any)
	WriteFile func(string, []byte, os.FileMode) error
}

type User

type User struct {
	ID          string       `json:"id"`
	Name        string       `json:"name"`
	Credentials []Credential `json:"credentials"`
}

User is the single logical WebAuthn identity managed by a Store.

func (User) WebAuthnCredentials

func (a User) WebAuthnCredentials() []webauthn.Credential

func (User) WebAuthnDisplayName

func (a User) WebAuthnDisplayName() string

func (User) WebAuthnID

func (a User) WebAuthnID() []byte

func (User) WebAuthnName

func (a User) WebAuthnName() string

Jump to

Keyboard shortcuts

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