Context Trust Model
Context attributes are the request-time values AuthzX evaluates alongside subject and resource data. Unlike subject.attributes or resource.attributes — which are persisted in the AuthzX control plane and gated behind write permissions — context is attached to each individual /v1/authorize call and discarded once the decision is returned.
That makes context powerful (it can express things like "the user's current IP" or "the current time") and also dangerous: if an attacker can influence a context value, they can influence the decision. This page explains the trust hierarchy so you source each attribute from a place your policies can safely rely on.
The trust hierarchy
From most trusted to least trusted:
- Server-derived (engine computed) — Values the AuthzX Agent generates itself. Nothing in the request can change them.
time— read from the agent's server clock.ip— taken from the TCP connection to your backend.geo— resolved server-side fromipvia a country lookup.
- Signed JWT claims — Values extracted from a JWT whose signature the agent has verified against the configured IdP.
mfa_verified,sub,email, custom claims.
- Server-stored attributes —
subject.attributesandresource.attributespersisted in AuthzX. Trusted because write access to them is itself gated by policy. - Caller-sent custom context — Anything in the
contextobject of the authorize request. Trusted only when your backend sets it from trusted state. Never trusted when it originates from an end-user request body.
The request flow
end user your backend (PEP) AuthzX Agent
┌────────┐ HTTP request ┌────────────────────┐ /v1/authorize ┌──────────────────────┐
│ browser│ ──────────────► │ your service │ ──────────────► │ AuthzX Agent │
│ mobile │ │ - verify JWT │ │ - evaluate policies │
│ etc. │ │ - build context │ │ - return decision │
└────────┘ └────────────────────┘ └──────────────────────┘
Your backend is the Policy Enforcement Point (PEP) — it's the trust boundary where you verify the caller, build the context, and enforce the decision. The AuthzX Agent is the authorization engine — it evaluates and returns the verdict.
The end user never talks to the agent directly. Your backend decides which values survive the crossing.
Per-attribute sourcing
| Attribute | Source from | Never source from |
|---|---|---|
ip | X-Forwarded-For parsed at your edge / load balancer | request body |
time | server clock on your backend or the PDP | request header or body |
mfa_verified | verified JWT claim | a raw boolean field on the request |
geo | server-side IP → country lookup | request body |
env, api_version | compile-time or config-loaded constant on your backend | request query/body |
Custom (session_risk, request_id, ...) | your backend's trusted internal state | anything the caller controls |
Bad: echoing user input into context
// DON'T — attacker sets env=dev and bypasses a production-only DENY policy
var body struct {
Env string `json:"env"`
}
_ = json.NewDecoder(r.Body).Decode(&body)
authzx.Authorize(ctx, authzx.AuthorizeRequest{
Subject: authzx.Subject{ID: userID},
Resource: authzx.Resource{ID: resourceID},
Action: "read",
Context: map[string]any{"env": body.Env}, // untrusted!
})
Good: sourcing from trusted backend state
// DO — env is a process-level constant, not caller input
const env = "production" // or loaded from your deployment config
mfaVerified, _ := claims["mfa_verified"].(bool) // from a verified JWT
authzx.Authorize(ctx, authzx.AuthorizeRequest{
Subject: authzx.Subject{ID: userID},
Resource: authzx.Resource{ID: resourceID},
Action: "read",
Context: map[string]any{
"env": env,
"mfa_verified": mfaVerified,
"ip": realClientIP(r), // from X-Forwarded-For at the edge
},
})
Same pattern in Node:
// Bad
await authzx.authorize({ ..., context: { env: req.body.env } })
// Good
const env = process.env.APP_ENV ?? "production"
await authzx.authorize({
...,
context: {
env,
mfa_verified: req.user.claims.mfa_verified === true,
ip: req.ip, // Express with `trust proxy` configured
},
})
Rule of thumb
If a policy would behave differently for env=dev vs env=prod, ask: can the user send a request that flips env to dev? If yes, you have a trust bug in your PEP, not a policy bug.
Related
- Policies — how ALLOW / DENY combine with context.
- Authorize API — the full request shape, including the
contextfield. - Subjects and Resources — the persisted-attribute side of the model.