pat

package
v1.11.0 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package pat implements personal access tokens — long-lived bearer credentials for programmatic API access (CI jobs, SDKs, curl) where the 15-minute JWT + refresh-cookie dance is impractical.

Security model (v1): a PAT authenticates AS its owning user — it inherits the user's role (including super-admin) within the resolved team. There are no granular scopes yet (v2); mitigations are the optional team pin, the optional expiry, ITERION_PAT_MAX_TTL, instant revocation, and audit rows on create/revoke/use.

Index

Constants

View Source
const TokenPrefix = "iap_"

TokenPrefix marks an iterion personal access token. The middleware branches on it to pick PAT verification over JWT parsing.

Variables

View Source
var (
	ErrNotFound = errors.New("pat: not found")
)

Sentinel errors.

Functions

func EnsureSchema

func EnsureSchema(ctx context.Context, db *mongo.Database) error

EnsureSchema creates the PAT indexes idempotently.

func HashToken

func HashToken(presented string) string

HashToken maps a presented plaintext to its storage hash.

func MintToken

func MintToken() (plaintext, hash, last4, fingerprint string, err error)

MintToken returns a fresh PAT plaintext (shown once) plus the at-rest fields. Same primitives as webhook tokens.

func VerifyToken

func VerifyToken(presented, storedHash string) bool

VerifyToken constant-time compares a presented token against a stored hash.

Types

type MemoryStore

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

MemoryStore is the in-process PAT store for tests and local mode. Keep semantics in lock-step with MongoStore.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

func (*MemoryStore) Create

func (s *MemoryStore) Create(_ context.Context, t Token) error

func (*MemoryStore) Get

func (s *MemoryStore) Get(_ context.Context, id string) (Token, error)

func (*MemoryStore) GetByTokenHash

func (s *MemoryStore) GetByTokenHash(_ context.Context, hash string) (Token, error)

func (*MemoryStore) ListByUser

func (s *MemoryStore) ListByUser(_ context.Context, userID string) ([]Token, error)

func (*MemoryStore) MarkUsed

func (s *MemoryStore) MarkUsed(_ context.Context, id string, at time.Time) error

func (*MemoryStore) Revoke

func (s *MemoryStore) Revoke(_ context.Context, id string, at time.Time) error

type MongoStore

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

MongoStore is the production PAT store.

func NewMongoStore

func NewMongoStore(db *mongo.Database) *MongoStore

func (*MongoStore) Create

func (s *MongoStore) Create(ctx context.Context, t Token) error

func (*MongoStore) Get

func (s *MongoStore) Get(ctx context.Context, id string) (Token, error)

func (*MongoStore) GetByTokenHash

func (s *MongoStore) GetByTokenHash(ctx context.Context, hash string) (Token, error)

func (*MongoStore) ListByUser

func (s *MongoStore) ListByUser(ctx context.Context, userID string) ([]Token, error)

func (*MongoStore) MarkUsed

func (s *MongoStore) MarkUsed(ctx context.Context, id string, at time.Time) error

MarkUsed is a best-effort stamp: a token revoked-and-purged mid-request is not an error here.

func (*MongoStore) Revoke

func (s *MongoStore) Revoke(ctx context.Context, id string, at time.Time) error

type Store

type Store interface {
	Create(ctx context.Context, t Token) error
	// GetByTokenHash is the auth-path lookup (no user scoping — the
	// hash IS the credential).
	GetByTokenHash(ctx context.Context, hash string) (Token, error)
	Get(ctx context.Context, id string) (Token, error)
	ListByUser(ctx context.Context, userID string) ([]Token, error)
	// Revoke marks the token unusable; rows are kept for audit.
	Revoke(ctx context.Context, id string, at time.Time) error
	MarkUsed(ctx context.Context, id string, at time.Time) error
}

Store persists tokens. Implementations: MongoStore (production) and MemoryStore (tests/local). Keep semantics in lock-step.

type Token

type Token struct {
	ID          string `bson:"_id" json:"id"`
	UserID      string `bson:"user_id" json:"user_id"`
	Name        string `bson:"name" json:"name"`
	TokenHash   string `bson:"token_hash" json:"-"`
	TokenLast4  string `bson:"token_last4" json:"token_last4"`
	Fingerprint string `bson:"fingerprint,omitempty" json:"fingerprint,omitempty"`
	// TeamID optionally pins the token to one team: requests
	// authenticate with that team active (membership re-checked at
	// every use). Empty → the user's default team.
	TeamID     string     `bson:"team_id,omitempty" json:"team_id,omitempty"`
	CreatedAt  time.Time  `bson:"created_at" json:"created_at"`
	ExpiresAt  *time.Time `bson:"expires_at,omitempty" json:"expires_at,omitempty"`
	LastUsedAt *time.Time `bson:"last_used_at,omitempty" json:"last_used_at,omitempty"`
	RevokedAt  *time.Time `bson:"revoked_at,omitempty" json:"revoked_at,omitempty"`
}

Token is one personal access token at rest. The plaintext is shown exactly once at mint; only the hash is persisted.

func (Token) Usable

func (t Token) Usable(now time.Time) bool

Usable reports whether the token can authenticate right now.

Jump to

Keyboard shortcuts

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