Security

Must: Secure Endpoints with OAuth 2.0

Every API endpoint needs to be secured using OAuth 2.0. Please refer to the official OpenAPI spec on how to specify security definitions in you API specification or take a look at the following example.

securityDefinitions:
  oauth2:
    type: oauth2
    flow: password
    tokenUrl: https://token.services.auth.zalando.com/oauth2/access_token
    scopes:
      fulfillment-order-service.read: Access right needed to read from the fulfillment order service.
      fulfillment-order-service.write: Access right needed to write to the fulfillment order service.

The example defines OAuth2 with password flow as security standard used for authentication when accessing endpoints; additionally, there are two API access rights defined via the scopes section for later endpoint authorization usage - please see next section.

It makes little sense specifying the flow to retrieve OAuth tokens in the securityDefinitions section, as API endpoints should not care, how OAuth tokens were created. Unfortunately the flow field is mandatory and cannot be ommited. API endpoints should always set flow: password and ignore this information.

Must: Define and Assign Access Rights (Scopes)

Every API needs to define access rights, called scopes here, and every endpoint needs to have at least one scope assigned. Scopes are defined by name and description per API specification, as shown in the previous section. Please refer to the following rules when creating scope names:

<api-scope> ::= <api-standard-scope> |            -- should be sufficient for majority of use cases 
                <api-resource-specific-scope> |   -- for special security access differentiation use cases 
                <api-pseudo-scope>                -- used to explicitly indicate that access is not restricted

<api-standard-scope>          ::= <application-id>.<access-type> 
<api-resource-specific-scope> ::= <application-id>.<resource-id>.<access-type>
<api-pseudo-scope>            ::= uid

<application-id> ::= <as defined via STUPS>
<access-type>    ::= read | write           -- might be extended in future
<resource-id>    ::= <free identifier following application-id syntax>

APIs should stick to standard scopes by default -- for the majority of use cases, restricting access to specific APIs (with read vs. write differentiation) is sufficient for controlling access for client types like merchant or retailer business partners, customers or operational staff. We want to avoid too many, fine grained scopes increasing governance complexity without real value add. In some situations, where the API serves different types of resources for different owners, resource specific scopes may make sense.

Some examples for standard and resource-specific scopes:

Application ID Resource ID Access Type Example
fulfillment-order read fulfillment-order.read
fulfillment-order write fulfillment-order.write
sales-order sales_order read sales-order.sales_order.read
sales-order shipment_order read sales-order.shipment_order.read

After scopes names are defined and the scope is declared in the security definition at the top of an API specification, it should be assigned to each API operation by specifying a security requirement like this:

paths:
  /sales-orders/{order-number}:
    get:
      summary: Retrieves a sales order
      security:
        - oauth2:
          - sales-order-service.sales_order.read

In very rare cases a whole API or some selected endpoints may not require specific access control. However, to make this explicit you should assign the uid pseudo access right scope in this case. It is the user id and always available as OAuth2 default scope.

paths:
  /public-information:
    get:
      summary: Provides public information about ... 
               Accessible by any user; no access rights needed. 
      security:
        - oauth2:
          - uid

Hint: you need not explicitly define the "Authorization" header; it is a standard header so to say implicitly defined via the security section.