serverauth

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package serverauth holds the request-admission seams shared by mast's network server surfaces (A2A — pkg/a2a; AG-UI — pkg/agui): pluggable bearer authentication (TokenValidator → Principal, with per-surface scope checks) and pluggable rate limiting (RateLimiter, in ratelimit.go). Both were first built for the A2A server (#78) and hoisted here so a single validator or limiter instance authenticates and admits across every surface (#84).

Like the surfaces that consume it, this package never imports the runtime: the daemon builds a validator/limiter from configuration and hands it to each server's New. It depends only on the standard library and golang.org/x/time, so it stays slim-embed-safe.

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidToken = errors.New("serverauth: invalid or unknown bearer token")

ErrInvalidToken marks an unrecognized bearer token; server surfaces map it to HTTP 401.

Functions

func IsLoopbackAddr

func IsLoopbackAddr(addr string) bool

IsLoopbackAddr reports whether a TCP listen address binds only a loopback interface. Conservative by design: an empty host (":7780"), the wildcards "0.0.0.0"/"::", and any hostname other than "localhost" all count as NON-loopback — when in doubt, treat the bind as network-reachable so a bind-policy check errs toward refusing. Server surfaces use it to refuse an unauthenticated bind beyond loopback. (pkg/attach keeps its own copy, predating this package.)

Types

type Principal

type Principal struct {
	Subject string
	Scopes  []string
	Tenant  string
}

Principal is the authenticated caller a TokenValidator resolves a bearer token to. Scopes gate per-skill / per-workload access. Tenant, when set, is the caller identity the rate limiter buckets on (RateLimitRequest.Tenant).

Tenant does NOT yet drive session isolation: ADK v2.1.0's IsolationScope is an event/task-level field (the workflow finish_task machinery), not a session-create or tenant seam (session.CreateRequest carries no scope). Multi-tenant session isolation is deferred pending an ADK session-scope seam or a mast-side user-namespacing design (docs/a2a-design.md "Multi-tenancy").

func (*Principal) HasScope

func (p *Principal) HasScope(want string) bool

HasScope reports whether the principal carries want. A nil principal carries no scopes.

type RateLimitRequest

type RateLimitRequest struct {
	// Subject is the authenticated caller (Principal.Subject); empty when
	// the endpoint is unauthenticated (all such callers share one bucket).
	Subject string

	// Tenant is the caller's tenant claim (Principal.Tenant), when set.
	// When present it is the caller identity the limiter buckets on, so a
	// multi-token tenant is limited as one caller.
	Tenant string

	// Workload is the target workload (skill) the call routes to.
	Workload string

	// Method is the protocol method being admitted (e.g. "message/send" for
	// A2A, "agui/run" for AG-UI).
	Method string
}

RateLimitRequest identifies one inbound call for an admission decision. A server fills it from the authenticated principal and the resolved target workload before dispatching the turn-driving verb.

type RateLimiter

type RateLimiter interface {
	// Allow reports whether the request may proceed. When ok is false,
	// retryAfter is an advisory backoff hint (zero if unknown).
	Allow(ctx context.Context, req RateLimitRequest) (ok bool, retryAfter time.Duration)
}

RateLimiter admits or refuses an inbound call before the server drives the turn. A server calls Allow once per turn-driving request; cheap control-plane verbs are not gated. A false return maps to a retryable refusal (A2A -32000 / AG-UI HTTP 429) with an advisory Retry-After. Nil disables rate limiting. Implementations must be safe for concurrent use.

type StaticBearerValidator

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

StaticBearerValidator validates against a fixed token→Principal map — the "static bearer tokens (for simple deployments)" validator from docs/a2a-design.md. It compares in constant time across every configured token so neither a miss nor a value mismatch leaks timing.

func NewStaticBearerValidator

func NewStaticBearerValidator(tokens map[string]*Principal) (*StaticBearerValidator, error)

NewStaticBearerValidator builds a validator from a token→Principal map. At least one non-empty token with a non-nil principal is required.

func (*StaticBearerValidator) Validate

func (v *StaticBearerValidator) Validate(_ context.Context, token string) (*Principal, error)

Validate resolves token to its principal, or ErrInvalidToken. It iterates every entry with a constant-time compare so total time does not depend on which (if any) token matched.

type TokenBucketLimiter

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

TokenBucketLimiter is the built-in RateLimiter: an independent token bucket per (caller, workload), where the caller is the request's Tenant if set else its Subject. Every bucket shares the same rate and burst. It admits a request only when a token is available immediately; a refused request reports the wait until the next token as retryAfter and does NOT consume future capacity.

The bucket map grows one entry per distinct (caller, workload) seen and is not evicted — consistent with the daemon's per-session pools at v0.2 single-instance scale (bounded eviction is a follow-on).

func NewTokenBucketLimiter

func NewTokenBucketLimiter(perSecond float64, burst int) (*TokenBucketLimiter, error)

NewTokenBucketLimiter builds a limiter admitting perSecond requests per (caller, workload) with the given burst. perSecond must be a finite value > 0 and burst must be >= 1.

func (*TokenBucketLimiter) Allow

Allow implements RateLimiter.

type TokenValidator

type TokenValidator interface {
	Validate(ctx context.Context, token string) (*Principal, error)
}

TokenValidator resolves a bearer token to a Principal. It returns ErrInvalidToken for a token it does not recognize (→ HTTP 401); any other error is treated as a validator fault (→ HTTP 500). Built-in: StaticBearerValidator. JWT/JWKS, Google IAM, and OAuth2 introspection validators are v0.3 (docs/a2a-design.md "Auth model") — the interface ships now as the extension point.

Jump to

Keyboard shortcuts

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