Skip to content

Authentication (JWT/OIDC) ​

Feature-gated

Build with --features auth to enable JWT/OIDC authentication.

Zion supports per-route JWT validation as an optional authentication gate. Tokens are validated before the request reaches the upstream, preventing unauthorized access at the edge.

Configuration ​

HMAC (symmetric) ​

For internal microservices using shared secrets:

toml
[auth_profile.internal]
# Prefer secret_env over a literal `secret` — it keeps the signing key out of
# zion.toml (and out of version control). It names an environment variable:
secret_env = "ZION_AUTH_INTERNAL_SECRET"
algorithm = "HS256"
issuer = "auth.internal"
audience = "api.internal"
forward_claims = true

Keep the HMAC secret out of the config file

A literal secret puts a live signing key in zion.toml — anyone who can read the file can forge valid tokens. Use secret_env (the name of an env var holding the secret); it wins over secret when both are set, and a named-but-missing/empty env var fails startup rather than silently continuing.

OIDC (asymmetric) ​

For external identity providers (Auth0, Keycloak, Okta):

toml
[auth_profile.oidc]
jwks_url = "https://auth.example.com/.well-known/jwks.json"
algorithm = "RS256"
issuer = "https://auth.example.com/"
audience = "api.example.com"
forward_claims = true

Route assignment ​

toml
[[route]]
path = "/api/protected/{*rest}"
upstream = "backend"
auth_profile = "oidc"
waf = true

Parameters ​

ParameterTypeDefaultDescription
secretstring—HMAC shared secret literal (HS256/HS384/HS512). Prefer secret_env.
secret_envstring—Name of an env var holding the HMAC secret. Preferred over secret; wins when both are set.
jwks_urlstring—JWKS endpoint URL (for RS256/ES256, auto-refreshed hourly)
algorithmstringHS256JWT algorithm. Auto-selects RS256 when jwks_url is set without secret
issuerstring—Expected iss claim (optional)
audiencestring—Expected aud claim (optional)
forward_claimsbooltrueInject X-Auth-Subject and X-Auth-Email headers to upstream

Supported algorithms ​

AlgorithmTypeUse Case
HS256, HS384, HS512Symmetric (HMAC)Internal microservices
RS256, RS384, RS512Asymmetric (RSA)OIDC providers (Auth0, Keycloak)
ES256, ES384Asymmetric (ECDSA)Modern OIDC providers

Behavior ​

  1. Missing Authorization header: Returns 401 Unauthorized
  2. Invalid/malformed token: Returns 403 Forbidden
  3. Expired token: Returns 401 Unauthorized with body token expired
  4. Valid token: Request proceeds to upstream with optional claim headers

Claim forwarding ​

When forward_claims = true, decoded claims are injected as headers:

HeaderClaimDescription
X-Auth-SubjectsubUser ID / subject
X-Auth-EmailemailUser email (if present in token)

These headers are reserved: Zion strips any inbound X-Auth-Subject / X-Auth-Email from the client on every request (regardless of the auth feature or whether a route has an auth profile) before the gate re-injects the verified values, so an upstream can trust them as authenticated. A client cannot forge them.

Token lifetime and revocation ​

Zion validates a token's signature, expiry (exp), and not-before (nbf) on every request, but it has no revocation or replay defense: there is no denylist, no OIDC introspection, and no jti/nonce replay check. A valid token is accepted until it expires, and can be replayed any number of times within its lifetime.

Consequences for operators:

  • Issue short-lived tokens. The token lifetime is your effective revocation window — a leaked token cannot be invalidated before exp. Minutes, not days.
  • A logout / key-compromise event cannot be enforced at the edge mid-lifetime; rotate the signing key (or JWKS) to invalidate outstanding tokens en masse.
  • If per-token revocation matters for your deployment, terminate auth at a service that maintains a denylist / introspection endpoint, and use Zion's gate as defense in depth.

JWKS refresh ​

  • JWKS is fetched at startup and refreshed every 1 hour
  • On fetch failure, retries with exponential backoff (5s, 10s, 20s, ... up to 1h)
  • HTTP client failure is retried indefinitely (never gives up permanently)
  • Clock skew tolerance: 30 seconds (leeway for distributed systems)

Bearer token extraction ​

The Authorization header is parsed case-insensitively per RFC 6750 Section 2.1:

http
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
Authorization: bearer eyJhbGciOiJSUzI1NiJ9...    # also accepted
Authorization: BEARER eyJhbGciOiJSUzI1NiJ9...    # also accepted

Build ​

bash
cargo build --release --features auth

Released under the MIT License. · Privacy & legal