Token Management Settings
Reach this screen by following Identity → Token Settings. These settings only affect the response body produced by the token endpoint; the default values preserve the current behavior.
Token Response Field Names
You can rename the standard field names in the JSON response body returned by the token endpoint, or drop a field from the response entirely. The default names follow the OAuth2 RFC 6749 standard.
| Field | Description |
|---|---|
| access_token field name | The name of the field that carries the access token. This field is mandatory per RFC 6749 §5.1; it can be renamed but cannot be removed from the response. |
| token_type field name | The name of the field that carries the token type. When "Include in response" is disabled, it is omitted. |
| expires_in field name | The name of the field that carries the token validity duration. When "Include in response" is disabled, it is omitted. |
| refresh_token field name | The name of the field that carries the refresh token. When "Include in response" is disabled, it is omitted. |
| scope field name | The name of the scope field returned alongside the token. When "Include scope field in response" is disabled, scope is not added to the response at all. |
These settings only affect the token response body. The scope claim embedded inside the JWT token itself is not renamed, so the receiving systems that validate the token are not affected.
expires_in Value Unit
By default the token endpoint returns the expires_in field in milliseconds (the legacy Apinizer behavior). RFC 6749 §5.1 defines expires_in as the token lifetime in seconds, so a strict OAuth2 client may misread the millisecond value (for example, interpret 60000 as ~16.6 hours instead of 60 seconds) and fail to refresh the token in time.
| Option | Behavior |
|---|---|
| Emit expires_in in Seconds (RFC 6749) | Disabled by default. When disabled, expires_in is returned in milliseconds (legacy behavior, preserved for backward compatibility). When enabled, expires_in is returned in seconds as required by RFC 6749 §5.1. |
This option affects only the response expires_in field. The JWT exp claim (an absolute timestamp) and the X-IssuedAt / X-ExpiresAt response fields are unaffected.
If your existing clients already compensate for the millisecond value, enabling this option will halve the lifetime they compute and may cause premature token refreshes. Leave it disabled for existing integrations; enable it for new integrations that expect RFC-compliant seconds.
A token issued to an API client always reports expires_in in seconds, regardless of this setting. This setting only governs tokens issued to a consumer.
Scope Validation Behavior
Scope indicates which permissions are requested with a token request and is used in the token acquisition with scope flow. The resolved scope is returned in the response body, alongside the token. This behavior works identically in both the "Manage From This Policy" and "Manage From ACL" management modes.
Which scopes are returned in the response depends on the two settings below.
Behavior on Scope Mismatch
Determines how the gateway behaves when some of the scopes requested by the client are not defined on the user or consumer.
| Option | Behavior |
|---|---|
| Strict — Return Error | If any requested scope is not defined, an HTTP 400 invalid_scope error is returned and no token is issued. Matches RFC 6749 §5.2. |
| Lenient — Issue Token with Intersection | A token is issued with only the defined scopes; invalid scopes are silently dropped. This is the default value. |
| Ignore Request — Use All Consumer Scopes | The requested scope list is ignored; the token is issued with all scopes defined on the user or consumer. |
On the screen, "(Default)" appears next to Strict — Return Error; however, the actual default value is Lenient — Issue Token with Intersection. New installations come with this value, and settings previously created with Ignore Request are changed to Lenient during the upgrade. Installations that deliberately selected Strict or Lenient are not changed.
Behavior When Scope Is Not Requested
Determines how the token's scope field is produced when the client requests no scope at all.
| Option | Behavior |
|---|---|
| Token Without Scope (Default) | If the request does not include scope, the token is issued without scope and the scope field is omitted from the response. |
| Use All Consumer Scopes | If the request does not include scope, all defined scopes are used and included in the response. |
Rejecting When the Principal Has No Roles
By default, when scopes are requested but the authenticated user or consumer has no roles at all, the gateway fails open: it issues a token with an empty scope instead of returning an error. Enable Reject When Principal Has No Roles to make this case a hard failure that returns an HTTP 400 invalid_scope error instead, which is useful for stricter diagnostics.
| Option | Behavior |
|---|---|
| Reject When Principal Has No Roles (Disabled by default) | When enabled and scopes are requested while the principal has no roles, an HTTP 400 invalid_scope error is returned. When disabled, a token with empty scope is issued (the legacy fail-open behavior). |
This setting has no effect under the Ignore Request — Use All Consumer Scopes mismatch mode, because that mode ignores the requested scope entirely.
An API client has no role/scope source of its own in this version — the "principal has no roles" case above is always true for one. So with Reject When Principal Has No Roles disabled (the default), an API client always gets a scopeless token; with it enabled, a scope-requesting API client is always refused with HTTP 400 invalid_scope.
For scope to be returned with a value, the relevant user or consumer must have a role (scope) defined. For the role definition steps, see the Token Acquisition with Scope section. If no role is defined, scope is returned empty even in Strict mode — unless Reject When Principal Has No Roles is enabled, in which case an HTTP 400 invalid_scope error is returned.
Revocation Strictness
Revoking a consumer, an API client, or an organization's consumers already kills every token those actions can reach: a stored (opaque) token is deleted outright, and an API client's already-issued JWTs are cut off by a stamped token cutoff that the gateway checks on every request. Revocation Strictness governs something else: what happens when a caller revokes one of its own JWT access tokens with the RFC 7009 revoke endpoint. A JWT is validated offline, so by default that call is accepted but the token keeps validating until it expires. The two JWT shapes that no cutoff can reach at all — see Known Limit: Legacy JWT Paths Outside the Revocation Cascade — can be ended early only this way.
| Option | Behavior |
|---|---|
| Degraded — Cutoff Only (Default) | No additional check is made anywhere, and nothing is written to a denylist. A caller's own RFC 7009 revoke of a JWT access token is accepted but has no effect: the token keeps validating until it expires on its own. Every token validation, on every path, pays nothing extra. |
| Strict — Cutoff + Denylist | The same RFC 7009 revoke call additionally records the JWT's hash in a dedicated denylist, bounded to the token's own remaining lifetime. From then on, a request carrying that JWT consults the denylist before the token is accepted — on every JWT path, including the paths where the gateway has resolved the consumer or API client — and so do token introspection and a token-exchange subject token. The cost is one extra cache lookup per validation. |
On the two JWT paths where no consumer or API client record is resolved, the extra lookup Strict adds is fail-closed: if the denylist cache cannot be reached, the request is refused rather than let through unchecked. This is deliberate — answering "not revoked" when the check simply could not run would quietly hand a Strict installation Degraded's guarantees at the worst possible moment — but it means a cache outage stops traffic on these two paths for a Strict tenant for as long as the outage lasts. On every path where the gateway has resolved the consumer or API client, an unreachable denylist does not stop traffic: the request is accepted, the token cutoff still applies, a warning is logged, and the denylist read on that path is skipped briefly so the outage adds no waiting time to each request. This is also why Degraded suits most installations: it is the setting most already run today and it costs nothing extra.
An entry Strict writes to its denylist lives for exactly as long as the token it denies would otherwise remain valid, and no longer — by default nothing evicts it sooner to free up space. This matters because a denylist entry is a negative assertion ("this token was revoked"): losing one early does not deny a request, it quietly allows one again before its real expiry. Degraded is unaffected, since it writes to no denylist at all.
An installation that would rather bound this denylist's size than let it grow unconstrained can still do so, through a dedicated setting (hazelcast.map.max.size.token-denylist) kept deliberately separate from the general cache-size setting described in Distributed Cache — tuning general cache memory can never silently shrink this security control by accident. Setting a bound is a deliberate trade-off, though: once it is reached, the least-recently-used entries are evicted (per node), and the revoked tokens they covered start validating again until their own expiry.
Revocation Strictness is a single tenant-wide setting; it cannot be set per policy, per API client, or per environment.
This version also stores a lookup-optimized fingerprint (a SHA-256 hash) alongside each token's own value, together with supporting database indexes, so that large token collections stay fast to search. This is an internal performance change only — it alters none of the behavior described on this page or on the Consumers page.