# Security in OpenAPI

# Security in OpenAPI

When designing an API, it's important to consider the security requirements for accessing the API. The OpenAPI Specification 3.1 provides a way to define security requirements at both the document and operation levels.

Firstly, "security" is a general term that covers multiple authentication and authorization systems commonly used to ensure API operations are used only by the intended actors.

OpenAPI divides security into two parts:

- **Security schemes**, which are defined as reusable components.
- **Security requirements**, which invoke the reusable security schemes either across the whole API or within specific operations.

The following simple example of an API key demonstrates the basic security structure defined in the OpenAPI Specification:

```yaml
security:
  - apiKey: []
components:
  securitySchemes:
    apiKey:
      type: apiKey
      name: Speakeasy-API-Key
      in: header
```

## Supported security schemes

Before you can reference a [security scheme](/openapi/security/security-schemes) as a requirement in the `security` section, it must be defined in the [Components Object](/openapi/components) under `securitySchemes`.

The OpenAPI Specification 3.1 supports the following security schemes:

- [API Key](/openapi/security/security-schemes/security-api-key)
- [HTTP Authorization](/openapi/security/security-schemes/security-http) (such as Basic, Digest, and Bearer)
- [OAuth 2.0](/openapi/security/security-schemes/security-oauth2)
- [OpenID Connect](/openapi/security/security-schemes/security-openid)
- [Mutual TLS](/openapi/security/security-schemes/security-mutualtls)

Once you've defined an API's security schemes, you can reference them in the `security` section of the OpenAPI document or at the operation level.

## The Security Requirement Object

A Security Requirement Object defines a map of security scheme names with an array of [scopes or roles](#security-requirement-scopes-or-roles) that are required to access an API (or specific operation).

The names **must** match the names of the [Security Scheme Objects](/openapi/security/security-schemes) defined in the [Components Object](/openapi/components) under the `securitySchemes` field.

<Table
  data={[
    {
      field: "{securitySchemeName}",
      type: "List<string>",
      required: "",
      description:
        "A list of [scopes or roles](#security-requirement-scopes-or-roles) required for the security scheme. If the security scheme type is `oauth2` or `openIdConnect`.",
    },
  ]}
  columns={[
    { key: "field", header: "Field" },
    { key: "type", header: "Type" },
    { key: "required", header: "Required" },
    { key: "description", header: "Description" },
  ]}
/>

## Global authentication vs endpoint authentication

Security can be applied at two levels in OpenAPI:

- **Global security:** The security specified is available for all operations.
- **Per-operation security:** The security is only applied to the operation, overriding any global-level security.

The following example demonstrates how to describe security at both levels:

```yaml
security:
  - apiKey: [] # Global security requirement
paths:
  /drinks:
    get:
      operationId: listDrinks
      summary: Get a list of drinks
    post:
      operationId: createDrink
      summary: Create a new drink
      security:
        - apiKey: [] # Per operation security requirement
```

The [`security`](https://spec.openapis.org/oas/v3.1.0#security-requirement-object) and [`securitySchemes`](https://spec.openapis.org/oas/v3.1.0#security-scheme-object/security-schemes) sections (representing the Security Object and Security Scheme Object, respectively) are most important in this example.

## Working with security requirements

Depending on the API, security requirements can be simple or complex. The following examples illustrate how to work with security requirements in OpenAPI.

### Simple API security

All the operations in an API may require an API key for access. You can define this requirement at the document level using the `security` section.

```yaml
security:
  - apiKey: []

paths:
  /drinks:
    get:
      operationId: listDrinks
      summary: Get a list of drinks
    post:
      operationId: createDrink
      summary: Create a new drink

components:
  securitySchemes:
    apiKey:
      type: apiKey
      name: Speakeasy-API-Key
      in: header
```

### Public reads, protected writes

A simple API might have some publicly accessible endpoints, but require an API key for others. You can use the `security` section to define the security requirements either for the entire API or for specific operations.

```yaml
security: [] # No global security requirements
paths:
  /drinks:
    get:
      operationId: listDrinks
      summary: Get a list of drinks
    post:
      operationId: createDrink
      summary: Create a new drink
      security:
        - apiKey: [] # This operation requires an API key
```

### Multiple security schemes

A more complex API may have different security requirements for different operations, or even allow multiple security schemes to be used interchangeably.

In the following example, the API can be accessed with either an API key or OAuth 2.0. OAuth 2.0 allows for more granular access control using the concept of scopes, which can be defined in the `securitySchemes` section and referenced in the `security` section for specific operations.

```yaml
# focus(3:16)
paths:
  /drinks:
    get:
      operationId: listDrinks
      summary: Get a list of drinks
      security:
        - apiKey: [] # Can be access with an API key, or...
        - oauth2: # an oauth2 token which has the read scope
            - read
    post:
      operationId: createDrink
      summary: Create a new drink
      security:
        - apiKey: [] # Can be accessed with an API key, or...
        - oauth2: # an oauth2 token which has the write scope
            - write

components:
  securitySchemes:
    apiKey:
      type: apiKey
      name: Speakeasy-API-Key
      in: header
    oauth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://example.com/oauth/authorize
          tokenUrl: https://example.com/oauth/token
          scopes:
            read: Read access to the API
            write: Write access to the API
```

## Security requirement scopes or roles in OpenAPI

When defining an OAuth 2.0 or OpenID Connect [Security Requirement Object](/openapi/security#security-requirement-object) for an operation, the `{securitySchemeName}` field should contain a list of the scopes or roles required for the security scheme.

For example, the following Security Requirement Object indicates that the `read` and `write` scopes are required for the `oauth2` security scheme:

```yaml
paths:
  /drinks:
    get:
      operationId: listDrinks
      summary: Get a list of drinks
      # Operation requires read and write scopes
      security:
        - oauth2:
            - read
            - write
      # ...
```

### Disabling security requirements for specific operations

You can disable security for a specific operation by providing an empty array (`[]`) in the list of security requirements.

In this example, the `POST` operation in the `/auth` path does not require security, despite the global security requirement of an API key:

```yaml
security:
  - apiKey: []
paths:
  /auth:
    post:
      operationId: authenticate
      summary: Authenticate with the API
      security: [] # Disable security for this operation
      # ...
```

### Optional security

You can make security optional by providing an empty object (`{}`) in the list of security requirements.

In this example, the API may be accessed with or without an API key:

```yaml
security:
  - apiKey: []
  - {}
```

### Optional security for specific operations

Similarly, you can make security optional for a specific operation by providing an empty object (`{}`) in the list of security requirements.

This does not disable the security requirements defined at the document level, but makes them optional for this specific operation.

In this example, the `GET` operation in the `/drinks` path may be accessed with or without an API key, but if authenticated, the response will include additional information:

```yaml
paths:
  /drinks:
    get:
      operationId: listDrinks
      summary: Get a list of drinks. If authenticated, this will include stock levels and product codes, otherwise it will only include public information.
      security:
        - {} # Make security optional for this operation
      # ...
```

### Requiring multiple security schemes

If multiple schemes are required together, then the [Security Requirement Object](/openapi/security#security-requirement-object) should be defined with multiple security schemes.

In this example, both an API key **AND** basic auth are required to access the API:

```yaml
security: # both apiKey AND basic are required
  - apiKey: []
    basic: []
```

### Complex authorization scenarios

You can use this **AND**/**OR** logic, along with optional (`{}`) security, in any combination to express complex authorization scenarios.

In this example, the API may be accessed with an API key **AND** OAuth 2.0, **OR** with basic authentication:

```yaml
security: # apiKey AND oauth2 OR basic
  - apiKey: []
    oauth2:
      - read
      - write
  - basic: []
```
