Upstream OAuth 2.0 Client Credentials Auth Policy
Secure your origin server with OAuth 2.0 authentication by automatically adding
an Authorization header to upstream requests. This policy enables your Zuplo
gateway to authenticate with any OAuth 2.0 identity provider that supports the
client credentials grant — such as Auth0, Okta, Keycloak, Microsoft Entra ID, or
your own authorization server.
With this policy, you'll benefit from:
- Enhanced Backend Security: Restrict access to your origin servers to only your Zuplo gateway
- Simplified Authentication: Delegate authentication and authorization to your gateway without backend code changes
- Automatic Token Management: Handle token acquisition, caching, and renewal automatically
- Provider Flexibility: Works with any standards-compliant OAuth 2.0 token endpoint, no provider-specific policy required
- Credential Security: Store sensitive client credentials securely in your Zuplo environment
Configuration
The configuration shows how to configure the policy in the 'policies.json' document.
Code
Policy Configuration
name<string>- The name of your policy instance. This is used as a reference in your routes.policyType<string>- The identifier of the policy. This is used by the Zuplo UI. Value should beupstream-oauth-client-credentials-inbound.handler.export<string>- The name of the exported type. Value should beUpstreamOAuthClientCredentialsInboundPolicy.handler.module<string>- The module containing the policy. Value should be$import(@zuplo/runtime).handler.options<object>- The options for this policy. See Policy Options below.
Policy Options
The options for this policy are specified below. All properties are optional unless specifically marked as required.
tokenUrl(required)<string>- The URL of the OAuth 2.0 token endpoint that issues the access token.clientId(required)<string>- The client ID used to authenticate with the token endpoint.clientSecret(required)<string>- The client secret used to authenticate with the token endpoint.scope<string>- Space-delimited list of scopes to request. When not set, thescopeparameter is omitted from the token request.audience<string>- The value of theaudienceform parameter sent to the token endpoint. Required by some identity providers such as Auth0. When not set, the parameter is omitted from the token request.credentialsIn<string>- Where the client credentials are sent on the token request.bodysendsclient_idandclient_secretas form parameters.headersends them with HTTP Basic authentication as described in RFC 6749 section 2.3.1. Allowed values arebody,header. Defaults to"body".additionalParameters<object>- Additional form parameters to include in the token request, for exampleresourcefor identity providers that require it.headerName<string>- The name of the header on the upstream request that the access token is set on. Defaults to"Authorization".headerScheme<string>- The scheme that prefixes the access token in the header. When the token response includes atoken_type, that value is used instead. Defaults to"Bearer".tokenRetries<number>- The number of times to retry fetching the token in the event of a failure. Defaults to3.expirationOffsetSeconds<number>- The number of seconds less than the token expiration to cache the token. Defaults to300.
Using the Policy
This policy authenticates your Zuplo gateway to OAuth 2.0-protected backend
services by automatically adding an access token to the Authorization header
(or a custom header) of upstream requests. It uses the OAuth 2.0 client
credentials grant against any token endpoint you configure, so it works with
Auth0, Okta, Keycloak, Microsoft Entra ID, and any other standards-compliant
identity provider.
How It Works
The policy performs the following operations:
- Requests an access token from the configured token endpoint using the client credentials grant
- Caches the token for subsequent requests until it nears expiration
- Adds the token to the configured header (default
Authorization) using thetoken_typereturned by the token endpoint, falling back to the configuredheaderScheme(defaultBearer) - Automatically handles token renewal when needed
Tokens are cached for expires_in - expirationOffsetSeconds seconds. If the
token endpoint doesn't return an expires_in value, the policy caches the token
conservatively as if it expired after 10 minutes (5 minutes with the default
expirationOffsetSeconds of 300) rather than caching it indefinitely.
Policy Configuration
Configure the policy with your identity provider's token endpoint and client credentials:
Code
Sending Client Credentials
By default (credentialsIn: "body"), the client credentials are sent as
client_id and client_secret form parameters in the token request body. While
RFC 6749 section 2.3.1
recommends HTTP Basic authentication, body is the default because it's the
method most widely accepted across identity providers (including Auth0, Okta,
Entra ID, and Keycloak) and avoids credential-encoding differences between
providers' Basic authentication implementations.
Set credentialsIn to header to send the credentials with HTTP Basic
authentication instead:
Code
Provider-Specific Parameters
Some identity providers require extra form parameters on the token request. Use
additionalParameters to send them, for example the resource parameter:
Code
The grant_type parameter is always client_credentials and the dedicated
clientId, clientSecret, scope, and audience options always take
precedence over entries in additionalParameters.
Usage Example
Apply the policy to routes that need to call your OAuth-protected backend:
Code
Security Considerations
- Store the client secret as an environment variable using
$env(VARIABLE_NAME)syntax - Grant the OAuth client the minimum scopes required to access your backend services
- Regularly rotate your client secrets according to your security policies
Read more about how policies work