OpenAPI 3.x SecurityRequirements with least-privilege scopes and token expiry documentation
0 reputation · 07 May 2020, 04:57 UTC
0 reputation · 07 May 2020, 04:57 UTC
Goal is to document least-privilege authentication using components.securitySchemes and per-operation security requirements in OpenAPI 3.x, with explicit permission boundaries per endpoint.
OpenAPI describes mechanisms such as OAuth2, HTTP bearer and API keys and allows minimal scopes to be listed per operation, but the specification is documentation only. It does not model token lifetime, refresh token flow details, or a normative way to document expired credential handling. Scope names are opaque strings with no defined semantics, and enforcement of scope boundaries is implementation specific.
With that constraint, what is a consistent way to document expected 401 Unauthorized and 403 Forbidden responses for expired credentials and insufficient scope in the same document? Should security requirements be limited to minimal scopes per operation to signal least-privilege intent, and how should refresh flow expectations be described without a standard field for token expiry?
35275 reputation · 07 May 2020, 13:46 UTC
To document least-privilege authentication in OpenAPI 3.x, you should define all possible scopes within the components/securitySchemes object and then reference only the minimum required scopes within the security requirement of each individual operation.
The specification allows you to override global security settings at the operation level. To signal least-privilege intent, avoid defining a broad global security requirement. Instead, explicitly list the narrowest possible scopes for every endpoint.
components:
securitySchemes:
OAuth2: # The central definition
type: oauth2
flows:
clientCredentials:
tokenUrl: https://auth.example.com/token
scopes:
read:read: "Read-only access to resources"
write:admin: "Administrative write access"
paths:
/resource:
get:
summary: Get resource
security:
- OAuth2: ["read:read"] # Minimal scope for this operation
responses:
'200':
description: Success
'401':
description: Unauthorized - Token expired or missing
'403':
description: Forbidden - Insufficient scope (e.g., requires read:read)
Because OpenAPI 3.x does not provide a normative field for token TTL (Time-to-Live) or refresh logic, these must be documented using descriptive text or vendor extensions. Since these details are usually consistent across the entire API, the description field of the security scheme is the most consistent location.
description field in components/securitySchemes to define the token lifetime (e.g., "Tokens expire after 3600 seconds") and the refresh mechanism.responses object for 401 and 403 to distinguish between authentication failure (expired/invalid token) and authorization failure (valid token, but missing the required scope).x-token-ttl: 3600.To ensure your documentation remains consistent with your implementation:
security block is explicitly declared in the components/securitySchemes scopes list.security block, preventing accidental fallback to overly-permissive global defaults.401 and 403 responses to guide the client on how to handle expiry vs. permission gaps.Diagnostic Detail Required: Are you using a standardized identity provider (like Okta or Auth0) or a custom implementation? This determines whether you should reference external RFCs (like RFC 6749) in your descriptions or provide detailed custom refresh flow steps.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 07 May 2020, 13:57 UTC
A small but important clarification on how OpenAPI 3.x interprets the security array: multiple SecurityRequirement objects under an operation are ORed, while scopes listed within a single requirement are ANDed.
This matters for least-privilege documentation. If you want to offer alternative auth methods, list them as separate objects. If you need all scopes together for one call, keep them in the same array. Mixing the two unintentionally broadens access.
Also, scopes are only meaningful for OAuth2 and OpenID Connect schemes. For http bearer and apiKey schemes the scopes array must be empty; processors will ignore it and consumers will be misled about required permissions. For those schemes, document permission boundaries in the scheme description instead.