auth

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package auth holds the token model, argon2id hashing, scope checks, and the SQLite-backed token store. (M2)

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidToken = errors.New("invalid token")

ErrInvalidToken is returned when the bearer can't be authenticated.

View Source
var ErrUnknownToken = errors.New("token not found")

ErrUnknownToken is returned by management calls when no row matches.

Functions

func DefaultPath

func DefaultPath(stateDir string) string

Path returns a likely default location for the token DB given a state dir.

func Has

func Has(scopes []string, required Scope) bool

Has reports whether scopes contains required, treating workspace:* as a supergrant over any workspace:<name>.

func ParseScopes

func ParseScopes(s string) ([]string, error)

ParseScopes splits a comma-separated list and validates each entry.

Types

type CreateOptions

type CreateOptions struct {
	Name             string
	Scopes           []string
	TTL              time.Duration // 0 = no expiry
	RateLimitRPM     int
	RateLimitTPD     int
	DebugCapture     bool
	DefaultVerbosity string
	// Principal opaquely groups tokens that should share a bridge
	// attachment. See Token.Principal.
	Principal string
}

CreateOptions describes a new token request.

type Scope

type Scope string

Scope is a single permission grant. Scopes follow PRD §6.6.

const (
	ScopeChat              Scope = "chat"
	ScopeSessionPersistent Scope = "session:persistent"
	ScopeAdmin             Scope = "admin"

	// ScopeWorkspaceWildcard grants access to every configured workspace.
	ScopeWorkspaceWildcard Scope = "workspace:*"

	// ScopeBridgeConnect lets a token open a /bridge websocket and register
	// the bridge daemon under the token's Principal. Chat tokens do NOT need
	// this scope — their bridge attachment happens implicitly when they
	// share a Principal with a connected bridge.
	ScopeBridgeConnect Scope = "bridge:connect"
)

func WorkspaceScope

func WorkspaceScope(name string) Scope

WorkspaceScope returns the scope value for one named workspace.

type Store

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

Store is the SQLite-backed token registry. It is safe for concurrent use.

func Open

func Open(path string) (*Store, error)

Open opens (and creates if needed) the token DB at path. The directory must already exist.

func (*Store) Authenticate

func (s *Store) Authenticate(ctx context.Context, bearer string) (*Token, error)

Authenticate resolves a bearer string to a Token. It first checks the in-memory cache; cache misses pay the argon2id cost.

func (*Store) Close

func (s *Store) Close() error

Close releases the underlying DB handle.

func (*Store) Count

func (s *Store) Count(ctx context.Context) (int, error)

Count returns how many tokens are stored.

func (*Store) Create

func (s *Store) Create(ctx context.Context, opts CreateOptions) (string, *Token, error)

Create inserts a new token row and returns the bearer string (which MUST be displayed to the user once — it is not recoverable from the DB) and the persisted Token record.

func (*Store) DB

func (s *Store) DB() *sql.DB

DB returns the underlying *sql.DB so other components (e.g. ratelimit) can share the same SQLite connection pool.

func (*Store) List

func (s *Store) List(ctx context.Context) ([]*Token, error)

List returns all tokens, ordered by creation time desc.

func (*Store) ResolveIDOrName

func (s *Store) ResolveIDOrName(ctx context.Context, idOrName string) (string, error)

ResolveIDOrName returns the token id for a string that might already be an id or might be a unique name. Unknown or ambiguous values return ErrUnknownToken. Useful for CLI commands that take an identifier.

func (*Store) Revoke

func (s *Store) Revoke(ctx context.Context, id string) error

Revoke deletes the token row and drops it from the cache.

func (*Store) Rotate

func (s *Store) Rotate(ctx context.Context, id string) (string, *Token, error)

Rotate generates a new bearer for an existing token id, invalidating the previous one. Scopes / limits / name are preserved.

func (*Store) SeedFromBearer

func (s *Store) SeedFromBearer(ctx context.Context, bearer string) (int, error)

SeedFromBearer is the M1→M2 migration path: if the DB has no tokens and a non-empty bearer is provided (e.g. from the legacy CCPROXY_TOKEN env), create one with chat scope and return it. Otherwise it's a no-op.

SeedFromBearer can only seed the env value if it is in the new ccp_<prefix>_<secret> format; arbitrary strings can't be backfilled because the prefix-indexed lookup needs the structured shape. Returns the count of tokens after the call so callers can warn appropriately.

func (*Store) SetDebugCapture

func (s *Store) SetDebugCapture(ctx context.Context, id string, enabled bool) error

SetDebugCapture flips the debug_capture flag on an existing token row. Takes effect on the next auth after the in-memory cache entry expires (default TTL 2m) — or immediately for tokens not yet cached.

type Token

type Token struct {
	ID           string
	Name         string
	Prefix       string
	Scopes       []string
	CreatedAt    time.Time
	LastUsedAt   *time.Time
	ExpiresAt    *time.Time
	RateLimitRPM int
	RateLimitTPD int
	DebugCapture bool
	DefaultVerb  string
	// Principal is an opaque identifier for the token's owner. Tokens
	// sharing a principal share a bridge attachment: when a bridge daemon
	// authenticated with principal P is connected, chat requests from
	// tokens with the same principal whose workspace would otherwise be
	// ephemeral resolve to the bridge mount instead. Empty principal means
	// the token participates in no bridge.
	Principal string
}

Token is the persisted record minus the secret hash (which never leaves the store).

func (*Token) HasScope

func (t *Token) HasScope(s Scope) bool

HasScope is a convenience over Has(t.Scopes, ...).

func (*Token) IsExpired

func (t *Token) IsExpired(now time.Time) bool

IsExpired reports whether t.ExpiresAt is set and in the past.

Jump to

Keyboard shortcuts

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