OpenAPI’s security schemes are fundamentally just declarations of intent, not enforcement mechanisms.
Let’s look at how you define API key authentication, which is a common way to secure your endpoints. The key is to tell clients how they should authenticate before they even attempt to call your API.
Imagine you have an API that requires an API key to be sent in a header. Here’s how you’d declare that in your OpenAPI specification (formerly known as Swagger):
openapi: 3.0.0
info:
title: My Secure API
version: 1.0.0
paths:
/items:
get:
summary: Get a list of items
security:
- ApiKeyAuth: [] # This is the crucial line
responses:
'200':
description: A list of items
components:
securitySchemes:
ApiKeyAuth: # This name must match the one in the path definition
type: apiKey
in: header # Or 'query' or 'cookie'
name: X-API-Key # The actual name of the header/query parameter/cookie
In this example:
securitySchemesis where you define all your security mechanisms.ApiKeyAuthis a custom name for this specific scheme. You can name it anything, but it’s good practice to be descriptive.type: apiKeytells OpenAPI this is an API key.in: headerspecifies that the API key should be sent in the HTTP request headers. Other common values arequery(for query parameters) andcookie(for cookies).name: X-API-Keyis the exact name of the header (or query parameter, or cookie) that your API expects. This is what the client will use.
Now, in the paths section, under the get operation for /items, we have security: - ApiKeyAuth: []. This line references the ApiKeyAuth scheme defined in components/securitySchemes. The empty array [] means there are no specific scopes required for this particular operation.
When a client tool (like Swagger UI, Postman, or an SDK generator) reads this spec, it understands that for the /items GET request, it needs to prompt the user for an API key and send it in the X-API-Key header.
This is what the security declaration looks like in action within the paths object. It’s a direct reference to a defined securityScheme.
If you wanted the API key to be in a query parameter instead, you’d change the in field:
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: query # Changed from header
name: api_key # Changed the name to a common query param convention
And the path declaration would remain the same:
paths:
/items:
get:
summary: Get a list of items
security:
- ApiKeyAuth: []
responses:
'200':
description: A list of items
The client would then expect the request to look like GET /items?api_key=YOUR_API_KEY.
The security property can also be defined at the root level of your OpenAPI document. If you do this, it applies to all operations by default, unless an operation explicitly overrides it.
openapi: 3.0.0
info:
title: My Secure API
version: 1.0.0
# Global security requirement
security:
- ApiKeyAuth: [] # Applies to all paths/operations by default
paths:
/items:
get:
summary: Get a list of items
# This operation inherits ApiKeyAuth from the root level
responses:
'200':
description: A list of items
/users:
post:
summary: Create a new user
# This operation also inherits ApiKeyAuth
responses:
'201':
description: User created
If an operation doesn’t want to use the global security scheme, or wants to use a different one, it would have its own security entry that either omits ApiKeyAuth or lists other schemes.
The most surprising thing about OpenAPI security schemes is how little they actually secure anything on their own; they are purely descriptive contracts for clients and documentation generators. The actual enforcement of checking that X-API-Key header (or query param, or cookie) and validating its value is entirely up to your API server’s implementation. Without server-side logic to read and validate the key, the security declaration is just flavor text.
If you define your API key using in: cookie, the name field refers to the cookie’s name, and the client tool will expect to set and send that cookie. The path and domain attributes of the cookie are not specified in OpenAPI, so your server implementation would need to handle setting those appropriately if it were also responsible for issuing the cookie.
Next, you’ll likely want to explore how to define rate limiting using OpenAPI.