Skip to main content
The policy package adds fine-grained authorization on top of sessions and API tokens. Policies are JSON documents of allow and deny statements. Evaluation is default-deny, and an explicit deny always wins.

Policy documents

  • Globs. * matches any run of characters, including /. A backslash escapes the next character. Matching is case sensitive.
  • Variables. {name} in a resource or condition value is replaced from the request attributes. Substituted values are escaped, so an attribute of * cannot widen a statement. If a variable is missing, an allow statement does not match and a deny statement still applies (fail closed).
  • Conditions. All must hold. Operators: equals, not_equals, in, not_in, ip_cidr, not_ip_cidr (key ip), time_window (two RFC 3339 bounds, either may be empty) and daily_window (HH:MM UTC, may wrap midnight). Positive operators are false for a missing key, negated ones are true, so a “deny unless from the office network” rule blocks unknown callers.
  • Parsing. policy.Parse rejects unknown fields, unknown versions and oversize documents. Use Policy.Marshal to write the canonical form.

Evaluating directly

HTTP middleware

RequirePolicy resolves the session, API token or agent token on every request, loads the policies attached to the user, the groups and roles your Subjects callback returns, and the token, then evaluates. A denial responds 403:
Every decision emits a policy.decision audit event with the action, resource, policy, statement and reason (set AuditDenyOnly to skip allows). Built-in attributes: principal.id, principal.kind, token.id, agent.name. Add more with Options.Attributes.

Permission boundary for tokens

Policies attached to a token (SubjectToken) form a boundary. The request must be allowed by the owner’s policies and by the boundary, and a boundary deny blocks it, so a token can only be narrower than its owner, never wider. An agent token is evaluated as its delegating human plus its own boundary.

Storage

policy.Storage (alias PolicyStorage) is an optional capability. policy.NewMemory() is the reference implementation, and a backend proves conformance with storagetest.RunPolicy. Suggested SQL schema:
PutPolicy upserts and keeps created_at. PoliciesFor orders by policy ID, then subject kind and ID.

Worked example: a deploy platform

A project admin can do everything in their project, a developer cannot touch production, and CI tokens may only deploy to staging.
Attach project-admin and developer to groups, and ci-staging to a CI token. Even if the CI token’s owner is a project admin, the token can only run deploy:create on staging. Removing a user from a group takes effect on the next request because group membership is resolved per request.
Last modified on October 7, 2026