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
- Variables
- func EnsureSchema(ctx context.Context, db *mongo.Database) error
- func HashToken(presented string) string
- func MintToken() (plaintext, hash, last4, fingerprint string, err error)
- func VerifyToken(presented, storedHash string) bool
- type MemoryStore
- func (s *MemoryStore) Create(_ context.Context, t Token) error
- func (s *MemoryStore) Get(_ context.Context, id string) (Token, error)
- func (s *MemoryStore) GetByTokenHash(_ context.Context, hash string) (Token, error)
- func (s *MemoryStore) ListByUser(_ context.Context, userID string) ([]Token, error)
- func (s *MemoryStore) MarkUsed(_ context.Context, id string, at time.Time) error
- func (s *MemoryStore) Revoke(_ context.Context, id string, at time.Time) error
- type MongoStore
- func (s *MongoStore) Create(ctx context.Context, t Token) error
- func (s *MongoStore) Get(ctx context.Context, id string) (Token, error)
- func (s *MongoStore) GetByTokenHash(ctx context.Context, hash string) (Token, error)
- func (s *MongoStore) ListByUser(ctx context.Context, userID string) ([]Token, error)
- func (s *MongoStore) MarkUsed(ctx context.Context, id string, at time.Time) error
- func (s *MongoStore) Revoke(ctx context.Context, id string, at time.Time) error
- type Store
- type Token
Constants ¶
const TokenPrefix = "iap_"
TokenPrefix marks an iterion personal access token. The middleware branches on it to pick PAT verification over JWT parsing.
Variables ¶
var (
ErrNotFound = errors.New("pat: not found")
)
Sentinel errors.
Functions ¶
func EnsureSchema ¶
EnsureSchema creates the PAT indexes idempotently.
func MintToken ¶
MintToken returns a fresh PAT plaintext (shown once) plus the at-rest fields. Same primitives as webhook tokens.
func VerifyToken ¶
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) GetByTokenHash ¶
func (*MemoryStore) ListByUser ¶
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) GetByTokenHash ¶
func (*MongoStore) ListByUser ¶
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.