Documentation
¶
Overview ¶
Package tokenauth contains small, cgo-free authorization data structures for token minting.
It is intentionally not a product policy engine. Product runtimes provide verified gate evidence, runtime measurement evidence, and optional budget storage. This package compiles a simple JSON policy and turns a mint request into an authorization decision that token services can consume.
Budget semantics: AuthorizeMint enforces the policy's budget rule only when the caller supplies a BudgetStore — a nil store means "budget enforcement happens elsewhere" and the budget_available check passes unconditionally. Deployments that want in-process enforcement use MemoryBudgetStore (single process) or implement BudgetStore over shared storage; any store error denies issuance (fail-closed).
Index ¶
- Constants
- Variables
- func VerifyPolicySidecar(policyJSON []byte, sidecar string, trustedPubs [][32]byte) error
- type AttesterSigner
- type BudgetRule
- type BudgetStore
- type Check
- type Defaults
- type Eligibility
- type GateKind
- type GateRule
- type IssuanceAuthorization
- type MeasurementRule
- type MemoryBudgetStore
- type MintConstraints
- type MintDecision
- type MintRequest
- type Policy
- type PolicySigner
- type Source
- type Subject
- type TokenFamily
- type TokenRule
Constants ¶
const ( ModeDevelopment = "development" ModeProduction = "production" AssuranceVerified = "verified" )
const ( // BucketSourceClaim pins bucket_id to a verified gate claim // (bucket_claim names which one). This is the default whenever // bucket_claim is set. BucketSourceClaim = "claim" // BucketSourceCaller declares that the service calling AuthorizeMint // derives and vouches for bucket_id itself (e.g. a salted source hash). // Production policies must opt in explicitly: a bucket key the far end // of the request gets to choose turns the budget into decoration. BucketSourceCaller = "caller" )
Bucket provenance: who is trusted to name the budget bucket for a gate.
const AuthorizationVersion = uint32(1)
AuthorizationVersion is the wire version; bump on breaking changes.
const DefaultAuthorizationTTLSecs = uint64(60)
DefaultAuthorizationTTLSecs is the authorization lifetime when the attester does not override.
Variables ¶
var ErrBudgetExceeded = errors.New("issuance budget exceeded for this bucket in the current window")
ErrBudgetExceeded is returned by Reserve when granting the request would exceed the budget limit for the current window.
Functions ¶
func VerifyPolicySidecar ¶ added in v0.1.7
VerifyPolicySidecar checks the sidecar signature over the exact policy bytes against any of the trusted operator keys. An empty trusted set means sidecar verification is not configured and always passes, matching the reference semantics.
Types ¶
type AttesterSigner ¶ added in v0.1.7
type AttesterSigner struct {
// contains filtered or unexported fields
}
AttesterSigner holds the attester's FAEST-128f key. The seed-to-key derivation is Go-specific (SHAKE256, like transparency.LogSigner); published keys and signatures are wire-compatible with the reference.
func NewAttesterSigner ¶ added in v0.1.7
func NewAttesterSigner(seed []byte) (*AttesterSigner, error)
NewAttesterSigner derives the attester key pair from a 32-byte seed.
func (*AttesterSigner) Public ¶ added in v0.1.7
func (s *AttesterSigner) Public() [32]byte
Public returns the 32-byte attester verification key.
func (*AttesterSigner) Sign ¶ added in v0.1.7
func (s *AttesterSigner) Sign(auth *IssuanceAuthorization, rho []byte) error
Sign fills auth.Sig (and the encoded JSON fields) over the canonical bytes. rho is the FAEST signer randomness (nil selects deterministic).
type BudgetRule ¶
type BudgetStore ¶
type Eligibility ¶
type GateRule ¶ added in v0.1.3
type GateRule struct {
Enabled bool `json:"enabled"`
BucketClaim string `json:"bucket_claim,omitempty"`
// BucketSource states where bucket_id comes from: "claim" (must match
// the verified claim named by bucket_claim) or "caller" (the calling
// service derives it). Production compilation fails if a gate used by
// an enabled token family declares neither.
BucketSource string `json:"bucket_source,omitempty"`
AddressClaim string `json:"address_claim,omitempty"`
AllowedHosts []string `json:"allowed_hosts,omitempty"`
}
type IssuanceAuthorization ¶ added in v0.1.7
type IssuanceAuthorization struct {
Version uint32 `json:"version"`
BindingHex string `json:"binding"`
RateLimitID []byte `json:"-"`
PolicyLabel string `json:"policy_label"`
MaxBatch uint32 `json:"max_batch"`
Exp uint64 `json:"exp"`
Iat uint64 `json:"iat"`
Sig []byte `json:"-"`
RateLimitIDB64 string `json:"rate_limit_id"`
SigB64 string `json:"sig"`
}
IssuanceAuthorization is the signed payload authorizing one blind-sign batch. The issuer learns only RateLimitID (a keyed hash), never the raw measurement. JSON field encodings match the reference (hex binding, standard-base64 rate_limit_id and sig).
func (*IssuanceAuthorization) Normalize ¶ added in v0.1.7
func (a *IssuanceAuthorization) Normalize() error
Normalize fills the raw fields from their encoded JSON forms (call after unmarshalling) and vice versa (call before marshalling).
func (*IssuanceAuthorization) SignedBytes ¶ added in v0.1.7
func (a *IssuanceAuthorization) SignedBytes() ([]byte, error)
SignedBytes is the canonical byte string the attester signs (everything except sig), byte-identical to the reference layout.
type MeasurementRule ¶
type MemoryBudgetStore ¶
type MemoryBudgetStore struct {
// contains filtered or unexported fields
}
MemoryBudgetStore is the reference BudgetStore: an in-memory, window-bucketed counter transpiled from the eat-pass InMemoryRateLimiter (core/src/ratelimit.rs). It is process-local — a multi-replica issuer must back the interface with a shared store instead — and it exists so the budget path has a working, tested implementation and so demos and single-process products need not write one.
Failure semantics match the reference: any Reserve error means the caller must deny issuance (AuthorizeMint fails the budget_available check), so a shared-store implementation that cannot reach its backend must return an error, never assume quota is available.
func NewMemoryBudgetStore ¶
func NewMemoryBudgetStore() *MemoryBudgetStore
NewMemoryBudgetStore returns an empty in-memory budget store.
func (*MemoryBudgetStore) Prune ¶
func (m *MemoryBudgetStore) Prune(now time.Time)
Prune drops counters for windows that ended before now (housekeeping, mirrors the reference's prune_before).
func (*MemoryBudgetStore) Reserve ¶
func (m *MemoryBudgetStore) Reserve(key string, amount, limit int, window time.Duration, now time.Time) error
Reserve consumes amount permits for key in the window containing now. Windows are epoch-aligned (now / window), matching the reference's epoch bucketing; a non-positive window degenerates to one second.
type MintConstraints ¶
type MintConstraints struct {
TokenFamily TokenFamily `json:"token_family"`
Count int `json:"count"`
KeyVersion uint32 `json:"key_version"`
BindingB64 string `json:"binding_b64"`
BudgetKey string `json:"budget_key"`
Origin string `json:"origin,omitempty"`
Address string `json:"address,omitempty"`
ExpiresAt int64 `json:"expires_at"`
}
type MintDecision ¶
type MintDecision struct {
Allow bool `json:"allow"`
Reason string `json:"reason"`
Checks []Check `json:"checks"`
Constraints MintConstraints `json:"constraints,omitempty"`
}
type MintRequest ¶
type MintRequest struct {
Subject Subject `json:"subject"`
Eligibility []Eligibility `json:"eligibility"`
TokenFamily TokenFamily `json:"token_family"`
Count int `json:"count"`
KeyVersion uint32 `json:"key_version"`
Origin string `json:"origin,omitempty"`
Address string `json:"address,omitempty"`
Binding []byte `json:"-"`
}
type Policy ¶
type Policy struct {
// contains filtered or unexported fields
}
func CompileJSON ¶
func (*Policy) AuthorizeMint ¶
func (p *Policy) AuthorizeMint(req MintRequest, budgets BudgetStore, now time.Time) MintDecision
type PolicySigner ¶ added in v0.1.7
type PolicySigner struct {
// contains filtered or unexported fields
}
PolicySigner holds an operator's FAEST-128f policy-signing key (Go-specific SHAKE256 seed derivation; wire-compatible signatures).
func NewPolicySigner ¶ added in v0.1.7
func NewPolicySigner(seed []byte) (*PolicySigner, error)
NewPolicySigner derives the operator key pair from a 32-byte seed.
func (*PolicySigner) Public ¶ added in v0.1.7
func (s *PolicySigner) Public() [32]byte
Public returns the 32-byte verification key operators publish.
func (*PolicySigner) SignPolicy ¶ added in v0.1.7
func (s *PolicySigner) SignPolicy(policyJSON, rho []byte) (string, error)
SignPolicy checks that policyJSON compiles, then returns the sidecar content: a standard-base64 FAEST-128f signature over the exact bytes. rho is the FAEST signer randomness (nil selects deterministic).
type Source ¶
type Source struct {
Version int `json:"version"`
Mode string `json:"mode"`
Defaults Defaults `json:"defaults"`
TokenFamilies map[string]TokenRule `json:"token_families"`
Gates map[string]GateRule `json:"gates"`
Measurements []MeasurementRule `json:"measurements,omitempty"`
Budgets map[string]BudgetRule `json:"budgets"`
}
type TokenFamily ¶
type TokenFamily string
const ( TokenBurn TokenFamily = "burn" TokenPrivateIdentity TokenFamily = "private_identity" TokenPolicyEmail TokenFamily = "policy_email" )
type TokenRule ¶
type TokenRule struct {
Enabled bool `json:"enabled"`
AllowedGates []string `json:"allowed_gates"`
AllowedOrigins []string `json:"allowed_origins,omitempty"`
BudgetGroup string `json:"budget_group"`
MaxBatch int `json:"max_batch,omitempty"`
RequiresAddressClaim bool `json:"requires_address_claim,omitempty"`
RequiresAttestation bool `json:"requires_attestation,omitempty"`
RequiresOrigin bool `json:"requires_origin,omitempty"`
}