auth

package
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package auth implements the OpenVaultDB auth MVP: an OAuth-style connect flow (consent → one-time code → scoped bearer token), capability grants persisted with hashed tokens, and HTTP middleware enforcing them.

The capability model follows the draft taxonomy in the spec hub (openvaultdb/openvaultdb spec/api/auth.md): namespaced capability strings such as "records:read", optionally collection-scoped as "records:read:contacts" (the spec's open question answered pragmatically — scoping is per collection, evaluated at enforcement time). Tokens are opaque bearer strings; only their SHA-256 lands on disk. The full JWT claim structure, refresh tokens, OIDC and passkeys stay with the spec (pending its architecture/security review) — this MVP keeps the wire surface small enough to swap those in without breaking applications.

Index

Constants

View Source
const (
	CapRecordsRead            = "records:read"   // GET/HEAD records, /query, /dtql
	CapRecordsWrite           = "records:write"  // PUT/POST/PATCH records, batch set/insert/update
	CapRecordsDelete          = "records:delete" // DELETE records, batch delete
	CapCollectionsRead        = "collections:read"
	CapSchemaRead             = "schema:read"      // inferred-schema endpoint
	CapDatabasesCreate        = "databases:create" // POST /v1/databases (server-level)
	CapPoliciesDiscover       = "policies:discover"
	CapPoliciesList           = "policies:list"
	CapPoliciesRead           = "policies:read"
	CapPoliciesAdmin          = "policies:admin"
	CapAccessExplain          = "access:explain"
	CapAccessSimulate         = "access:simulate"
	CapAccessDiagnostics      = "access:diagnostics"
	CapAccessInspectProtected = "access:inspect-protected"
)

Actions an application capability can name (subset of the spec taxonomy that is meaningful against the MVP API surface).

View Source
const CodeTTL = 5 * time.Minute

CodeTTL is how long a one-time authorization code stays exchangeable.

View Source
const TokenTTL = time.Hour

TokenTTL is how long an issued application token stays valid. The spec drafts 15-minute app tokens with refresh; the MVP has no refresh tokens yet, so it uses the spec's API-key tier (1 hour) — apps re-run the connect flow after expiry.

Variables

This section is empty.

Functions

func BearerToken

func BearerToken(r *http.Request) string

BearerToken extracts the bearer token from the Authorization header.

func HashToken

func HashToken(token string) string

HashToken returns the SHA-256 hex of a token — the only form persisted.

func NewGrantID

func NewGrantID() (string, error)

NewGrantID generates a short random grant identifier (8 random hex bytes = 16 hex chars).

func NewToken

func NewToken() (string, error)

NewToken mints a cryptographically random opaque bearer token.

Types

type Capability

type Capability struct {
	Action     string `json:"action"`
	Collection string `json:"collection,omitempty"`
}

Capability is one parsed grant entry: an action, optionally scoped to a single collection ("" = all collections of the granted database).

func ParseCapabilities

func ParseCapabilities(csv string) ([]Capability, error)

ParseCapabilities parses a comma-separated capability list.

func ParseCapability

func ParseCapability(s string) (Capability, error)

ParseCapability parses "records:read" or "records:read:contacts".

func (Capability) String

func (c Capability) String() string

String renders the capability back to its wire form.

type Config

type Config struct {
	// OwnerToken grants administrative capabilities; database policies still apply.
	OwnerToken string
	// Store holds application grants and pending authorization codes.
	Store *Store
}

Config is the server-side auth configuration. A nil *Config means auth is disabled (the local-dev default documented in the threat model).

func (*Config) Middleware

func (cfg *Config) Middleware(next http.Handler) http.Handler

Middleware implements the spec's Layer-1 token validation: it authenticates every request (401 on missing/invalid tokens except on public paths) and attaches the Principal for the handlers' Layer-2 capability enforcement.

type Grant

type Grant struct {
	// Subject and Actor are provisioned by owner administration. Membership is
	// resolved per request, never accepted from the token consumer.
	Subject       *access.PrincipalRef `json:"subject,omitempty"`
	Actor         *access.PrincipalRef `json:"actor,omitempty"`
	ID            string               `json:"id"`              // short random identifier (8 hex bytes)
	Label         string               `json:"label,omitempty"` // human display name
	TokenHash     string               `json:"tokenHash"`
	PrincipalType string               `json:"principalType"`        // "application" (MVP)
	PrincipalID   string               `json:"principalId"`          // client_id
	DatabaseID    string               `json:"databaseId,omitempty"` // "" = server-level grant (e.g. databases:create)
	Capabilities  []Capability         `json:"capabilities"`
	IssuedAt      time.Time            `json:"issuedAt"`
	ExpiresAt     time.Time            `json:"expiresAt,omitempty"` // zero = never expires
	RevokedAt     *time.Time           `json:"revokedAt,omitempty"`
}

Grant is one issued application token: the token itself is NOT stored — only its SHA-256 hex — so the grants file never holds usable credentials.

func (*Grant) Expired

func (g *Grant) Expired(now time.Time) bool

Expired reports whether the grant has reached its expiry. A zero ExpiresAt never expires.

func (*Grant) Revoked

func (g *Grant) Revoked() bool

Revoked reports whether the grant has been revoked.

func (*Grant) ValidateIdentity added in v0.4.0

func (g *Grant) ValidateIdentity() error

ValidateIdentity rejects partial or malformed delegation bindings. Legacy client-only grants remain application credentials and never imply a user.

type Principal

type Principal struct {
	Owner bool   // owner token: administrative capability authority; data ACL still applies
	Grant *Grant // application grant when Owner is false
}

Principal is the authenticated caller attached to a request context.

func FromRequest

func FromRequest(r *http.Request) *Principal

FromRequest returns the authenticated principal attached by Middleware, or nil when the request is unauthenticated (public path or auth disabled).

func (*Principal) Allows

func (p *Principal) Allows(databaseID, action, collection string) bool

Allows reports whether the principal may perform action on the collection of the database. Owner allows everything. An empty collection means the action targets the database as a whole (listing collections, queries whose target collection cannot be determined) — that requires an UNSCOPED grant entry, so collection-scoped grants never leak beyond their collection.

Database matching is on the GRANT side only: a grant with an empty DatabaseID is SERVER-LEVEL and matches any requested database (including the empty requested id used for server-level checks such as databases:create). A grant with a concrete DatabaseID matches only that exact database — it never matches a server-level check, because the requested "" differs from its concrete id.

type Store

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

Store holds issued grants (persisted as JSON with hashed tokens) and pending one-time codes (in-memory). Safe for concurrent use.

func OpenStore

func OpenStore(filePath string) (*Store, error)

OpenStore loads (or initializes) the grants file. Truly expired grants (non-zero ExpiresAt in the past) are dropped on load; revoked grants are kept for the audit trail.

func (*Store) CreateGrant

func (s *Store) CreateGrant(g *Grant, token string) error

CreateGrant hashes token, sets IssuedAt, stores and persists the grant. The caller must populate g.DatabaseID, g.Capabilities, g.Label, g.ExpiresAt (zero = never expires) before calling. On success g.ID, g.TokenHash, g.IssuedAt, g.PrincipalType are filled in.

func (*Store) ExchangeCode

func (s *Store) ExchangeCode(code, clientID string) (token string, g *Grant, err error)

ExchangeCode consumes a code (one-time use) and, when it is valid, unexpired and bound to the same client, mints and persists a grant. Returns the raw bearer token — the only time it ever exists outside the client.

func (*Store) ListGrants

func (s *Store) ListGrants() []*Grant

ListGrants returns all grants (including revoked ones) sorted by IssuedAt ascending. Never exposes token secrets.

func (*Store) Lookup

func (s *Store) Lookup(token string) *Grant

Lookup resolves a bearer token to its grant, or nil when unknown, expired, or revoked.

func (*Store) PutCode

func (s *Store) PutCode(code, clientID, redirectURI, databaseID string, caps []Capability)

PutCode registers a one-time authorization code.

func (*Store) RevokeGrant

func (s *Store) RevokeGrant(id string) (*Grant, bool)

RevokeGrant sets RevokedAt on the grant with the given ID and persists. Returns the updated grant and true on success; nil and false when unknown. Revoking an already-revoked grant is idempotent (updates RevokedAt if not set).

Jump to

Keyboard shortcuts

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