apiKey, Bearer, OAuth2 and OpenID Connect
A REST API without correctly documented security requirements is a black box for consumers. OpenAPI 3.x offers four security scheme types that can be made directly usable in the Swagger UI, if you know how to model them correctly, combine them globally and endpoint-specifically, and control them granularly with scopes.
Table of Contents
- 1. Why security schemes are decisive in API documentation
- 2. The four security scheme types at a glance
- 3. apiKey: simple, but with pitfalls
- 4. http Bearer: the standard for modern APIs
- 5. Modeling OAuth2 flows completely
- 6. OpenID Connect: federation and discovery
- 7. Defining scopes granularly and consistently
- 8. Global vs. endpoint-specific security
- 9. Security scheme types compared
- 10. Summary
- 11. FAQ
1. Why security schemes are decisive in API documentation
OpenAPI documents without correct security definitions are incomplete from a consumer's perspective. When a frontend developer sees in the Swagger UI that an endpoint can return a 401 status, but no security scheme is attached, they have to look up in the source code or project documentation which authentication method the endpoint expects. That costs time and leads to errors during integration.
The OpenAPI Specification defines security schemes as part of the components section and allows them to be referenced globally for all operations or individually per endpoint. The result: the Swagger UI shows an "Authorize" button through which users can enter their credentials, and testing tools like Postman import the authentication configuration directly from the OpenAPI document. Correct security scheme modeling makes the difference between documentation that is actually usable and one that only exists as a reference.
The topic becomes especially relevant when multiple authentication methods exist in parallel: an internal API for microservices might use API keys, while the public-facing API requires OAuth2. OpenAPI lets you define both schemes and reference them at different endpoints, without redundant description and with clear semantics for tooling and audits.
2. The four security scheme types at a glance
OpenAPI 3.x defines four security scheme types: apiKey, http, oauth2 and openIdConnect. Each type has a different mechanism, different semantic meaning and different Swagger UI representation. Choosing the right type is not a matter of style, it determines how tooling handles the scheme, which fields are required and how code generators produce the authentication code.
A common mistake is using apiKey for bearer tokens, even though the http type with scheme: bearer would be the semantically correct choice. Both send a value in the Authorization header, but tooling treats them differently: for http bearer, clients automatically add the "Bearer " prefix, for apiKey they do not. These subtle differences have a direct impact on generated client libraries and test configurations.
# components/securitySchemes: all four types defined
components:
securitySchemes:
# Type 1: apiKey, sends value in header, query or cookie
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: >
Internal service-to-service key. Include the raw key value.
Do NOT add a "Bearer " prefix, the server expects the key directly.
# Type 2: http, standard HTTP auth schemes (basic, bearer, digest)
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: >
JWT issued by the authorization server. Include in the
Authorization header. The "Bearer " prefix is added automatically
by conforming clients.
# Type 3: oauth2, full OAuth2 flow support
OAuth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl: https://auth.mironsoft.de/oauth/authorize
tokenUrl: https://auth.mironsoft.de/oauth/token
refreshUrl: https://auth.mironsoft.de/oauth/token
scopes:
read:orders: Read order data
write:orders: Create and update orders
admin:users: Manage user accounts (requires admin role)
# Type 4: openIdConnect, discovery document URL
OpenIDConnect:
type: openIdConnect
openIdConnectUrl: https://auth.mironsoft.de/.well-known/openid-configuration
3. apiKey: simple, but with pitfalls
The apiKey type is the simplest security scheme type and is suitable for APIs that expect a static key for authentication, typically internal APIs, webhook receivers or partner APIs with limited scope. The key can be transmitted in the request header (in: header), in a query parameter (in: query) or in a cookie (in: cookie).
The most common pitfall: API keys in query parameters appear in server logs, proxy logs and browser history. This is a security risk that should be explicitly addressed in the documentation. OpenAPI has no dedicated way to flag security risks, that belongs in the scheme's description field. If you model API keys with an expiration date and rotation, you should document that too, since OpenAPI only describes the mechanism, not the lifetime.
Another practical point: if an API has two parallel apiKey schemes, for example one key for read and one for write operations, both can be defined in components/securitySchemes and referenced individually at endpoints. That immediately shows consumers which endpoints require which key, without that information being hidden in the description.
4. http Bearer: the standard for modern APIs
The http type with scheme: bearer is the correct OpenAPI modeling for JWT-based authentication and other bearer token approaches. The optional bearerFormat field has no functional meaning for validation, it is a hint for tooling and documentation readers. Typical values are JWT, opaque or SAML.
An important detail for Swagger UI integration: when a user enters a bearer token in the Swagger UI, the UI adds the "Bearer " prefix automatically. That means users should only enter the token itself, without prepending "Bearer ". This information belongs in the scheme's description field, because it is not intuitive for testers and leads to frequent 401 errors during manual testing.
# Bearer Auth with detailed description for Swagger UI users
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
**JWT Bearer Token Authentication**
Obtain a token via POST /auth/token with your credentials.
Enter ONLY the token, the "Bearer " prefix is added automatically.
Token structure (claims):
- sub: user ID
- roles: array of role strings
- exp: expiry as Unix timestamp (default: 3600s)
Example token endpoint response:
```json
{
"access_token": "eyJhbGci...",
"token_type": "Bearer",
"expires_in": 3600
}
```
paths:
/orders:
get:
summary: List orders
security:
- BearerAuth: [] # bearer token required, no scopes for http scheme
responses:
'200':
description: Order list
'401':
description: Missing or invalid token
'403':
description: Insufficient permissions
/health:
get:
summary: Health check, public endpoint
security: [] # override: no auth required for this endpoint
responses:
'200':
description: Service is healthy
5. Modeling OAuth2 flows completely
OpenAPI 3.x supports all four OAuth2 flows: authorizationCode, implicit, clientCredentials and password. In practice, today authorizationCode (with PKCE for public clients) and clientCredentials for machine-to-machine communication dominate. The implicit flow is considered deprecated, the password flow is considered insecure, neither should be modeled in new APIs anymore, except to document legacy behavior.
Scope modeling in the OAuth2 scheme is the most important difference from other scheme types: scopes are named permissions that the authorization server grants to the token and that the API checks during authorization. OpenAPI lets you name these scopes in the security scheme definition and reference them per endpoint. Tooling, Swagger UI, Postman, generated clients, uses this information to help users request the correct scopes for a token.
# OAuth2 with multiple flows for different client types
components:
securitySchemes:
OAuth2:
type: oauth2
flows:
# Browser-based apps and mobile: use authorizationCode + PKCE
authorizationCode:
authorizationUrl: https://auth.mironsoft.de/oauth/authorize
tokenUrl: https://auth.mironsoft.de/oauth/token
refreshUrl: https://auth.mironsoft.de/oauth/token
scopes:
'read:products': View product catalog
'write:products': Create and update products
'read:orders': View own orders
'write:orders': Place and cancel orders
'admin:orders': Manage all orders (requires admin role)
'admin:users': Manage user accounts (requires admin role)
# Server-to-server: no user interaction, uses client credentials
clientCredentials:
tokenUrl: https://auth.mironsoft.de/oauth/token
scopes:
'service:read': Read-only service access
'service:write': Read-write service access
paths:
/products:
post:
summary: Create product
security:
- OAuth2:
- write:products # minimum required scope
responses:
'201':
description: Product created
'403':
description: Scope write:products not present in token
/admin/orders:
get:
summary: List all orders (admin)
security:
- OAuth2:
- admin:orders # admin scope required
- BearerAuth: [] # OR: internal service with Bearer token
responses:
'200':
description: All orders
6. OpenID Connect: federation and discovery
The openIdConnect type is the least used and at the same time the most powerful security scheme type in OpenAPI. It references an OpenID Connect discovery URL (/.well-known/openid-configuration), from which tooling and clients can automatically derive all endpoint URLs, supported flows and scopes. That saves maintenance effort: if the authorization server changes its endpoints, only the discovery document needs to be updated, not the OpenAPI schema.
A practical point for Swagger UI: the UI supports openIdConnect starting with version 4.x and can automatically derive the authorization endpoint for the authorizationCode flow from the discovery URL. For older Swagger UI versions, a parallel OAuth2 scheme that spells out the endpoints explicitly is recommended. Both schemes can be defined at the same time in components/securitySchemes, one for tooling compatibility, one for semantic correctness.
7. Defining scopes granularly and consistently
Scope naming is one of the most common sources of inconsistency in API designs. If one team uses read_orders and another orders:read, confusion arises among consumers and problems occur with scope validation in the authorization server. The recommendation: establish a naming convention and follow it consistently across all schemes. Common patterns are resource:action (e.g. orders:read), action:resource (e.g. read:orders) and hierarchical scopes such as api.orders.read.
An important concept: scopes in OpenAPI describe the minimum permissions a token must have for an endpoint to process the request. They are no guarantee that the API performs no further checks, a business logic check (for example "Is this user allowed to see this specific order?") is not a scope check. This distinction should be made clear in the API documentation so that consumers do not develop false expectations about the scope mechanism.
8. Global vs. endpoint-specific security
OpenAPI lets you define a security scheme at the root level of the document, which then applies as the default for all operations. Endpoints that need a different configuration (for example public endpoints without auth, or endpoints with higher permissions) override the global security object with their own. An empty array (security: []) explicitly disables authentication for that endpoint.
This pattern is especially useful for APIs where the vast majority of endpoints expect the same authentication: the global security scheme sets the default, and only exceptions are explicitly documented. That reduces redundancy in the YAML and makes clear which endpoints are deliberately accessible without authentication, information that matters for security audits and API reviews.
| Security scheme type | Typical use case | Swagger UI support | Scope support |
|---|---|---|---|
apiKey |
Internal APIs, partner keys, webhooks | Full | No |
http bearer |
JWT-based APIs, modern REST APIs | Full | No (in scheme) |
oauth2 |
Public APIs, third-party integration | Full | Yes |
openIdConnect |
Federation, SSO, discovery-based | From v4.x | Yes (via discovery) |
9. Global and endpoint-specific configuration
In practice, production APIs often combine several security scheme types. A typical configuration: a global Bearer scheme for all authenticated endpoints, OAuth2 with scopes for third-party access, and an apiKey scheme for monitoring and health endpoints called by internal tools. This combination can be modeled cleanly in OpenAPI without endpoints being documented twice.
# Global security + per-endpoint overrides
openapi: 3.1.0
info:
title: Mironsoft Shop API
version: 2.0.0
# Global default: all endpoints require Bearer auth
security:
- BearerAuth: []
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
OAuth2:
type: oauth2
flows:
clientCredentials:
tokenUrl: https://auth.mironsoft.de/oauth/token
scopes:
'api:read': Read access
'api:write': Write access
paths:
/orders:
get:
summary: List orders, uses global Bearer auth
# No security key needed, inherits global BearerAuth: []
responses:
'200':
description: OK
/health:
get:
summary: Health check, public, no auth
security: [] # explicitly disable all auth
responses:
'200':
description: OK
/metrics:
get:
summary: Prometheus metrics, internal key only
security:
- ApiKeyAuth: [] # override global: internal key instead of Bearer
responses:
'200':
description: Metrics in text/plain
/integrations/orders:
get:
summary: Order feed for partners, OAuth2 or Bearer
security:
- OAuth2:
- api:read # partner OAuth2 with scope
- BearerAuth: [] # OR: internal Bearer token
responses:
'200':
description: Order feed
10. Summary
OpenAPI security schemes are not an optional documentation extra, they are the foundation for usable API documentation, functioning tooling and efficient security audits. The right scheme type makes the difference: apiKey for static keys, http bearer for JWT, oauth2 when scopes and flows matter, openIdConnect for federation scenarios. Name scopes consistently and coherently, set global security defaults and explicitly document exceptions with security: [].
The Swagger UI makes security schemes immediately usable: users can enter credentials and test endpoints directly. Postman and other tools import the configuration automatically. Code generators like openapi-generator produce authentication code matching the security scheme type. Investing in careful security scheme modeling pays off in less support effort, faster integration and better auditability.
OpenAPI Security Schemes: The essentials at a glance
Scheme types
apiKey for static keys, http bearer for JWT, oauth2 for flows with scopes, openIdConnect for discovery-based federation.
Global security
Root-level security sets the default for all endpoints. Overriding per endpoint is possible. security: [] makes an endpoint explicitly public.
Scopes
Only OAuth2 and OIDC support scopes natively. Establish a naming convention (resource:action) and follow it consistently. Scopes describe minimum permissions, not business logic.
Swagger UI
All scheme types except OIDC are fully supported. Bearer input: token only, no "Bearer " prefix. Document the hint in the description field.