Every API endpoint must be protected and armed with authentication and authorization.
As part of the API definition you must specify how you protect your API using
either the http
typed bearer
or oauth2
typed security schemes defined in the
OpenAPI Authentication Specification.
The majority of our APIs (especially the company internal APIs) are protected
using JWT tokens provided by the platform IAM token service. In these situations
you should use the http
typed
Bearer Authentication
security scheme — it is based on OAuth2.0 {RFC-6750}[RFC 6750] defining the standard header
Auhorization: Bearer <token>
.
The following code snippet shows how to define the bearer security scheme.
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
The bearer security schema can then be applied to all API endpoints, e.g. requiring
the token to have api-repository.read
scope for permission as follows (see
also {MUST} define and assign permissions (scopes)):
security:
- BearerAuth: [ api-repository.read ]
In other, more specific situations e.g. with customer and partner facing APIs you
may use other OAuth 2.0 authorization flows as defined by {RFC-6749}[RFC 6749].
Please consult the
OpenAPI OAuth 2.0 Authentication
section for details on how to define oauth2
typed security schemes correctly.
Note: Do not use OpenAPI oauth2
typed security scheme flows (e.g. implicit
)
if your service does not fully support it and implements a simple bearer token scheme,
because it exposes authentication server address details and may make use of redirection.
APIs must define permissions to protect their resources. Thus, at least one permission must be assigned to each API endpoint.
The naming schema for permissions corresponds to the naming schema for hostnames and event type names. Please refer to {MUST} follow naming convention for permissions (scopes) for designing permission names and see the following examples.
Application ID | Resource ID | Access Type | Example |
---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note: APIs should stick to component specific permissions without resource extension to avoid the complexity of too many fine grained permissions. For the majority of use cases, restricting access for specific API endpoints using read or write is sufficient.
The defined permissions are than assigned to each API endpoint based on the security schema (see example in previous section) by specifying the security requirement as follows:
paths:
/business-partners/{partner-id}:
get:
summary: Retrieves information about a business partner
security:
- BearerAuth: [ business-partner-service.read ]
In some cases a whole API or selected API endpoints may not require specific
permissions, e.g. if information is public or protected by object level
authorization. To make this explicit you should assign the uid
pseudo
permission, that is always available as OAuth2 default scope in Zalando.
paths:
/public-information:
get:
summary: Provides public information about ...
Accessible by any user; no permissions needed.
security:
- BearerAuth: [ uid ]
Hint: Following a minimal a minimal API specification approach, the
Authorization
-header does not need to be defined on each API endpoint, since
it is required and so to say implicitly defined via the security section.
As long as the functional naming is not yet supported by our permission registry, permission names in APIs must conform to the following naming pattern:
<permission> ::= <standard-permission> | -- should be sufficient for majority of use cases
<resource-permission> | -- for special security access differentiation use cases
<pseudo-permission> -- used to explicitly indicate that access is not restricted
<standard-permission> ::= <application-id>.<access-mode>
<resource-permission> ::= <application-id>.<resource-name>.<access-mode>
<pseudo-permission> ::= uid
<application-id> ::= [a-z][a-z0-9-]* -- application identifier
<resource-name> ::= [a-z][a-z0-9-]* -- free resource identifier
<access-mode> ::= read | write -- might be extended in future
This pattern is compatible with the previous definition.
Note: This naming convention only applies to scopes for service-to-service communication using the Platform IAM tokens. For IAM systems with other naming rules (e.g. Zalando Partner IAM), the naming should be consistent with the existing conventions of those systems.