oauth Guard
oauth Guard
Defines a guard with OAuth 2.0 support.
The oauth guard acquires access tokens from an external Identity Provider (IdP) so that Zilla can authorize requests to upstream APIs on behalf of itself, or on behalf of a caller who has already been authenticated some other way. Which flow runs, and which options apply, depends on the configured grant.
grant | Purpose |
|---|---|
client-credentials | Zilla obtains a token for itself, using a client ID and secret. |
jwt-bearer | Zilla obtains a token for itself, using a self-signed JWT assertion (RFC 7523). |
token-exchange | Zilla exchanges a caller's already-validated credential for a token scoped to a downstream audience (RFC 8693). |
client-credentials
Zilla exchanges a client ID and secret for its own service-account token, then reuses the cached token for every request routed through the guard until it expires.
guards:
my_oauth_guard:
type: oauth
options:
grant: client-credentials
endpoint: https://auth.example.com/oauth/token
scope: api:read
credentials:
client-id: my-service
client-secret: my-secretjwt-bearer
Also machine-to-machine, but Zilla authenticates with a self-signed JWT assertion signed by a private key instead of a shared secret — the shape expected by IdPs such as Google service accounts.
guards:
my_oauth_guard:
type: oauth
options:
grant: jwt-bearer
endpoint: https://auth.example.com/oauth/token
scope: api:read
credentials:
issuer: my-service@example.iam.gserviceaccount.com
private-key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----The assertion's iss claim is credentials.issuer and its aud claim is the token endpoint; its lifetime is controlled by the zilla.guard.oauth.assertion.lifetime.seconds engine property.
token-exchange
Zilla exchanges a credential already validated by another guard for a token scoped to a different audience — for example, swapping a caller's validated JWT for a token accepted by a downstream API.
guards:
jwt0:
type: jwt
options:
issuer: https://auth.example.com
audience: https://gateway.example.com
my_oauth_guard:
type: oauth
store: sessions
options:
grant: token-exchange
endpoint: https://auth.example.com/oauth/token
audience: https://api.example.com
via: "${guarded['jwt0'].credentials}"
callback: /oauth/callbackvia names the upstream guard supplying the subject credential to exchange. callback is the redirect URI Zilla listens on to complete the exchange when the subject credential arrives through a redirect rather than being presented directly. Configure store whenever Zilla runs with more than one worker or replica, since the pending exchange must be readable regardless of which worker receives the callback.
Configuration (* required)
store
string
The name of the store used by this guard.
options*
object
The oauth specific options. Which properties apply, and which are required, depends on options.grant.
options:
grant: client-credentials
endpoint: https://auth.example.com/oauth/token
scope: api:read
credentials:
client-id: my-service
client-secret: my-secretoptions.grant*
enum[token-exchange,client-credentials,jwt-bearer]
The OAuth grant used to acquire access tokens.
options.endpoint*
string
Token endpoint URL, used for the token, and refresh, requests.
options.audience
string
Audience requested from the IdP. Required for token-exchange; also sent as the audience parameter for client-credentials.
options.scope
string
Space-delimited scope requested from the IdP. After a token is granted, the scope the IdP actually granted is available to downstream bindings as the guard's scope attribute, which may differ from the requested value.
options.via
string
References another guard's credentials, using ${guarded['<guard-name>'].credentials}, supplying the subject whose token is being exchanged. Required for token-exchange.
options.callback
string
Redirect URI Zilla listens on to complete a pending authorization when the IdP redirects back with state and code query parameters. Required for token-exchange. Not permitted for client-credentials or jwt-bearer, since neither grant redirects.
options.challenge
integer
Number of seconds before the access token's expiration to begin signaling a pending challenge, so specific protocol bindings can proactively renew it.
options.credentials
object
Client authentication material for client-credentials and jwt-bearer.
options:
credentials:
client-id: my-service
client-secret: my-secretcredentials.client-id
string
Client ID sent as HTTP Basic authentication when requesting a token. Required for client-credentials.
credentials.client-secret
string
Client secret sent as HTTP Basic authentication when requesting a token. Required for client-credentials.
credentials.private-key
string
PEM-encoded PKCS8 RSA private key used to sign the jwt-bearer assertion. Required for jwt-bearer.
options:
credentials:
private-key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----credentials.issuer
string
Value embedded as the iss claim of the jwt-bearer assertion. Required for jwt-bearer.
Engine Properties
Two engine-level properties, set with zilla start -P, affect every oauth guard:
| Property | Default | Purpose |
|---|---|---|
zilla.guard.oauth.assertion.lifetime.seconds | 600 | Lifetime of the self-signed JWT assertion built for the jwt-bearer grant. |
zilla.guard.oauth.nonce.ttl.seconds | 300 | How long a pending token-exchange authorization stays valid while waiting for the IdP's redirect callback. |

