Documentation
¶
Overview ¶
Package token is the gateway's credential check: which issuer it trusts, which audiences it accepts, and the keys it verifies against.
It is deliberately thin. The identity DECISION — what a claim means, which org a request acts in, who pays, which headers get minted — lives in hanzoai/authz and hanzoai/authz/edge, because three consumers each having their own reading of one contract is what drifted into a live escalation. What is left here is the part that is genuinely this deployment's: the ISSUER and AUDIENCE policy, named by the environment variables this deployment already sets.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var DefaultAudiences = []string{
"hanzo-app",
"hanzo-console",
"hanzo-chat",
"hanzo-id",
"hanzo-admin-guard",
"admin-console",
"hanzo-world",
"cowork",
"https://api.hanzo.ai",
}
DefaultAudiences is the baked allowlist: the known IAM client_ids (each app's `aud` is its client_id) plus the API origin. Forwards-only — append a new client_id, never remove one. Override entirely with GATEWAY_ALLOWED_AUDIENCES.
var ErrNoToken = errors.New("token: no credential")
ErrNoToken reports that no credential was present, so a caller can tell "missing" from "invalid" and fall through to a session or anonymous path.
Functions ¶
func AudiencesFromEnv ¶
func AudiencesFromEnv() []string
AudiencesFromEnv resolves the audience allowlist. GATEWAY_ALLOWED_AUDIENCES (comma-separated), when set, fully replaces the baked default. Otherwise the baked list is used, with the legacy single-value AUTH_AUDIENCE folded IN when set — it widens, never narrows, so a deployment still pinned to AUTH_AUDIENCE keeps that value inside an already-inclusive set rather than collapsing the allowlist to one entry. The result is never empty, so the check is always enforced.
Types ¶
type Config ¶
type Config struct {
JWKSURL string
Issuer string
// Audiences is the allowlist of acceptable `aud` values, with OR semantics: a
// token passes when its audience matches ANY entry.
//
// It is enforced HERE rather than in authz.Verify, which deliberately does not
// check audience — IAM sets `aud` per RFC 8707 to the requesting CLIENT, so the
// claim names which client asked for the token, not which resource server may
// accept it. Checking it is therefore a POLICY an edge may hold ("I accept tokens
// minted for these consoles") and not part of reading a token. An empty list
// disables the check; AudiencesFromEnv never returns empty, so it is always on.
Audiences []string
JWKSTTL time.Duration
}
Config is the edge's verification policy.
func ConfigFromEnv ¶
func ConfigFromEnv() Config
ConfigFromEnv reads the AUTH_* variables, so every binary in this module agrees on the IAM authority.
type Validator ¶
type Validator struct {
// contains filtered or unexported fields
}
Validator binds a Config to the edge's key cache for repeated verification.
func NewValidator ¶
NewValidator builds a Validator from cfg.
func (*Validator) VerifyRaw ¶
VerifyRaw verifies a credential held out of band — an OAuth2 code-exchange handler checking the token it just received, say.
Signature, issuer and expiry are authz.Verify's; the audience allowlist is this edge's, applied after. The order matters: an unverified token's claims are not evidence of anything, so nothing is read off it before the signature holds.