Documentation
¶
Overview ¶
Package token provides single-use, time-limited tokens for the Gas ecosystem. Tokens are used for magic links, email verification, password reset, and invite links. They implement gas.Service but NOT gas.Authenticator — tokens are verified once and consumed.
Index ¶
- Variables
- func New(opts ...Option) ...
- type Config
- type Option
- type Provider
- type Service
- func (s *Service) Close() error
- func (s *Service) Init() error
- func (s *Service) Issue(ctx context.Context, subject, purpose string, ttl time.Duration) (string, error)
- func (s *Service) Name() string
- func (s *Service) Revoke(ctx context.Context, rawToken string) error
- func (s *Service) RevokeAllByPurpose(ctx context.Context, subject, purpose string) error
- func (s *Service) Verify(ctx context.Context, rawToken, purpose string) (subject string, err error)
- type Settings
Constants ¶
This section is empty.
Variables ¶
var ( // ErrTokenInvalid indicates that the token does not exist or has already // been consumed. ErrTokenInvalid = errors.New("invalid token") // ErrTokenExpired indicates that the token has expired. ErrTokenExpired = errors.New("token expired") )
Sentinel errors for token operations.
Functions ¶
func New ¶
func New(opts ...Option) func(gas.DatabaseProvider, gas.Logger, gas.MigrationManager, gas.ConfigProvider) *Service
New captures options and returns a DI-injectable constructor.
Types ¶
type Config ¶
type Config struct {
env.WithGasEnv
Token Settings
}
Config holds token service settings.
func DefaultConfig ¶
func DefaultConfig() *Config
DefaultConfig returns a Config with sensible defaults.
type Option ¶
type Option func(*Service)
Option configures a Service.
func WithConfig ¶
WithConfig sets a custom configuration, skipping auto-bind from ConfigProvider.
type Provider ¶
type Provider interface {
// Issue generates a random token, stores its hash with purpose, subject, and
// expiry, and returns the raw token. If ttl is 0, DefaultTTL is used.
Issue(ctx context.Context, subject, purpose string, ttl time.Duration) (string, error)
// Verify hashes the raw token, looks it up by hash, unconditionally deletes it,
// then checks purpose match and expiry. Returns the subject on success.
//
// The token is deleted before validation so that a single presentation always
// consumes it — regardless of whether the caller supplied the wrong purpose or
// the token has expired. This keeps a simple invariant: once the raw secret has
// been presented, it cannot be reused.
Verify(ctx context.Context, rawToken, purpose string) (subject string, err error)
// Revoke deletes a specific token by its raw value.
Revoke(ctx context.Context, rawToken string) error
// RevokeAllByPurpose deletes all tokens for a subject with the given purpose.
RevokeAllByPurpose(ctx context.Context, subject, purpose string) error
}
Provider defines the contract for managing and validating single-use tokens.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service manages single-use tokens. It implements gas.Service.
func (*Service) Init ¶
Init validates configuration, initializes the store, and starts the background cleanup goroutine.
func (*Service) Issue ¶
func (s *Service) Issue(ctx context.Context, subject, purpose string, ttl time.Duration) (string, error)
Issue generates a random token, stores its hash with purpose, subject, and expiry, and returns the raw token. If ttl is 0, DefaultTTL is used.
func (*Service) RevokeAllByPurpose ¶
RevokeAllByPurpose deletes all tokens for a subject with the given purpose.
func (*Service) Verify ¶
Verify hashes the raw token, atomically fetches-and-deletes it, then checks purpose match and expiry. Returns the subject on success.
The fetch-and-delete happens in a single atomic store operation so that concurrent Verify calls for the same raw token cannot both succeed: only one caller observes the record, the other sees ErrTokenInvalid.
Deletion is unconditional on validation outcome: once the raw secret has been presented, it is burned regardless of whether purpose matches or the token has expired. This keeps a simple invariant — once the raw secret has been presented, it cannot be reused — and prevents an attacker who has the hash but guesses the wrong purpose from retrying indefinitely.
Trade-off: a bug that sends the wrong purpose string will silently consume a valid token. This is the preferable failure mode — it surfaces the bug immediately rather than masking cross-flow confusion.
type Settings ¶
type Settings struct {
// DefaultTTL is the default token lifetime when Issue is called with ttl == 0.
DefaultTTL time.Duration
// TokenLength is the number of random bytes used for token generation.
TokenLength int
// CleanupInterval is the interval for the expired token cleanup goroutine.
CleanupInterval time.Duration
// CleanupTimeout is the timeout for the expired token cleanup goroutine.
CleanupTimeout time.Duration
}
Settings represents the token configuration values.