Outpost OAuth scope enforcement
The Outpost supports path-based OAuth scope enforcement via OAuthScopeEnforcer. When enabled, each request’s JWT scp or scope claim is checked against the scopes required for the requested path. Requests that pass JWT validation but lack the required scope receive HTTP 403 with an X-Scope-Required header identifying the missing scope.
Scope enforcement is opt-in — it is disabled by default to preserve backward compatibility with environments that use API key authentication or do not include scope claims in their tokens.
Overview
Section titled “Overview”Scope enforcement runs after JWT signature validation. The enforcement flow for each request:
- JWT validator authenticates the token (
JWTValidator.validate()). - If
OAUTH_SCOPE_ENFORCEMENT=trueand anOAuthScopeEnforceris configured,enforce()is called with the decoded JWT claims and the request path. - The enforcer looks up the required scopes for the path in the
oauth_scopes.path_required_scopesmap. - If required scopes are found, the enforcer checks that each required scope is present in the token’s
scporscopeclaim. - On mismatch: raise
ScopeEnforcementError→ HTTP 403 +X-Scope-Required: <scope>. - If no required scopes are configured for the path, the request passes.
- API-key-authenticated requests bypass scope enforcement entirely.
Enabling scope enforcement
Section titled “Enabling scope enforcement”Set the environment variable on the Outpost:
OAUTH_SCOPE_ENFORCEMENT=true| Variable | Default | Description |
|---|---|---|
OAUTH_SCOPE_ENFORCEMENT | false | Set to true to enable path-based scope enforcement. When false, JWT validation still runs but scope claims are not checked. |
Scope enforcement requires JWT validation to be active (OAUTH_JWT_PUBLIC_KEY or OAUTH_JWKS_URL must be set). If JWT validation is disabled, scope enforcement has no effect.
Policy bundle configuration
Section titled “Policy bundle configuration”Scope requirements are configured in the oauth_scopes block of the policy bundle. Set these values in the Admin Portal and they propagate to all Outposts on the next policy sync (default 60-second interval).
{ "oauth_scopes": { "allowed_scopes": ["api:read", "api:write", "admin:read", "admin:write"], "path_required_scopes": { "/v1/chat/completions": ["api:write"], "/v1/models": ["api:read"], "/admin/api/*": ["admin:read"] } }}allowed_scopes
Section titled “allowed_scopes”An optional list of scopes that the Outpost recognises as valid. This field is informational — the enforcer does not reject tokens for having scopes outside this list, only for lacking required scopes on specific paths.
path_required_scopes
Section titled “path_required_scopes”A map from path pattern to a list of required scope strings. The enforcer checks all listed scopes; the token must include every scope in the list for the matched path.
{ "path_required_scopes": { "/v1/chat/completions": ["api:write"], "/admin/api/budget/status": ["admin:read"], "/admin/api/*": ["admin:read"] }}The request path is matched against the map keys in order. The first matching entry is used.
Wildcard paths
Section titled “Wildcard paths”Path keys support a trailing * wildcard:
| Pattern | Matches |
|---|---|
/v1/chat/completions | Exact path only |
/admin/api/* | Any path under /admin/api/ |
* | All paths |
The wildcard matches any suffix. It does not support mid-path wildcards (e.g. /v1/*/completions is not supported — use exact paths or suffix wildcards only).
Scope claim format
Section titled “Scope claim format”The enforcer reads scopes from the JWT payload in two formats:
String format (space-delimited, RFC 6749 standard):
{ "scp": "api:read api:write audit:read"}Array format:
{ "scope": ["api:read", "api:write", "audit:read"]}Both scp and scope claim names are checked. The enforcer first checks scp; if absent, it checks scope. If both are absent, scope enforcement treats the token as having no scopes.
Denied request response
Section titled “Denied request response”When a request is denied for insufficient scope:
HTTP/1.1 403 ForbiddenX-Scope-Required: api:writeContent-Type: application/json
{"detail": "Insufficient scope. Required: api:write"}The X-Scope-Required header contains the first scope that was missing. If multiple scopes are required and several are absent, only the first missing scope is reported in the header (the full list is included in the JSON body).
Interaction with API key authentication
Section titled “Interaction with API key authentication”Scope enforcement applies only to JWT-authenticated requests. Requests authenticated via Authorization: Bearer <api-key> (Outpost HMAC API key) bypass scope enforcement entirely. This allows existing API key integrations to continue operating without modification when scope enforcement is enabled.
Platform scope constants
Section titled “Platform scope constants”The Arbitex Platform uses these scope constants for M2M OAuth tokens:
| Scope | Description |
|---|---|
api:read | Read access to the chat completions and models endpoints |
api:write | Write access to the chat completions endpoint |
admin:read | Read access to admin API endpoints |
admin:write | Write access to admin API endpoints |
audit:read | Read access to audit log endpoints |
dlp:read | Read access to DLP rule and result endpoints |
Configure path_required_scopes using these constants for compatibility with Platform-issued M2M tokens.
Example: minimal production configuration
Section titled “Example: minimal production configuration”Lock the chat completions endpoint to api:write and allow all other paths for any valid JWT:
{ "oauth_scopes": { "path_required_scopes": { "/v1/chat/completions": ["api:write"] } }}With OAUTH_SCOPE_ENFORCEMENT=true, requests to /v1/chat/completions without api:write in the token scope receive HTTP 403. All other paths remain accessible to any authenticated JWT.
See also
Section titled “See also”- Outpost JWT validation — Configure
OAUTH_JWT_PUBLIC_KEY,OAUTH_JWKS_URL, and JWT validation options. - OAuth M2M API guide — How Platform M2M tokens are issued and what claims they carry.
- Outpost policy simulator — Test policy bundle configuration including scope rules before deployment.