This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Security and Compliance

This section covers security requirements intended to secure your API both from unauthorized use and from authorized misuse. It also covers relevant, security-related topics such as CORS headers and browser security.

1 - Authorization

How to determine whether a user, system, or other principal has the necessary permissions to perform an action or access a resource.

For resources and actions that require authorization, the only permitted method is via Bearer Tokens as per RFC 7519. While the process of obtaining these tokens is outside the scope of this contract, they are likely issued by a security token service (STS) such as may exist in a federated OIDC or OAuth2 environment.

The structure and evaluation of this token is not up to us, though we strongly encourage you follow best practices such as OAuth2 Security Topics

POST /namespace/v1/resource HTTP/1.1
Authorization: Bearer <JWT Access Token>

JWT Token Payload

Assuming a token is properly decoded and validated, the following payload can be extracted and inspected for scopes and other non-normative permission markers.

{
  "sub": "00000000-0000-0000-0000-000000000000",
  "azp": "authorized_client_id",
  "domain": "example.com",
  "context": "00000000-0000-0000-0000-000000000000",
  "iss": "https://issuer.example.com",
  "exp": 1603075483,
  "iat": 1603073683,
  "jti": "00000000-0000-0000-0000-000000000000",
  "scope": "openid profile email"
}

Considered Alternatives

Cookies

Cookies are problematic at best, and downright dangerous at worst. OWASP best practices recommend that cookies are explicitly domain bound, meaning that you are forced to a specific public api design, that of a single gateway to access all of your services. This is a contract, not a design document, and we want to avoid dictating your infrastructure.

Basic Auth

Basic Auth requires the use of explicit credentials for every api request, meaning that the resource owner’s username and password need to be known by every system that wishes to make a request.

API Key

API Keys are not a bad idea, however we strongly prefer that these are exchanged for bearer tokens with a limited TTL. This makes sure that API Keys can be quickly revoked, as they are only redeemed at a single service.

ID Tokens / Access Tokens

We do not explicitly define which access tokens may or may not be used, because I don’t know your use case. For modifying or reading a user’s own data, an ID token may be sufficient. For modifying or reading a different kind of resource, an access token may be more appropriate.

2 - Do not use cookies

Cookies are a bad idea. Don’t use them.

But what about

No.

But there’s this library

No.

Well everyone else

No.

Why?

  • They destroy privacy, requiring additional engineering work and support for GDPR and other privacy regulations.
  • They are domain bound. To use them on multiple domains requires attaching them to the TLD, which starts to leak.
  • They leak. Everywhere.
  • Every last marketing tracker adds their own cookies to try to figure out who you are, and you have no control over what the browser does with those. A single visit to your company’s marketing site can add 20 cookies to your browser, and those will be attached to every single request to your API. Even if each of them only consumes 4KB of data, that’s 80KB of data that you’re sending on every request that you don’t need. It adds up quick.
  • There’s always a new XSS attack.
  • It makes you susceptible to CSRF attacks.
  • There are size limits for how much data you can store in a cookie.
  • There are limits to the number of cookies a browser will store per domain, which will conflict with the above leaking.
  • You don’t need them.

In summary, even if you follow all of the OWASP recommendations for cookies, they are still a bad idea. Cookies create privacy concerns, security risks, performance impacts, technical debt, user experience overhead, and legal compliance concerns. There are better options available.

What should I use instead?

Please see our section on Authorization.

3 - Cross-Origin Resource Sharing

A full implementation of the W3C’s Cross-Origin Resource Sharing (CORS) specification is required.

A proper implementation of the W3C’s Cross-Origin Resource Sharing CORS specification can greatly improve the utility of your API, and permits deployment decoupling between your clients and your UI. It can also cause quite a bit of hand-wringing by your security team, if not used correctly. The trick to know is that all CORS vulnerabilities stem from the use of Cookies for session management.

For the purposes of this contract, CORS support is required. While you can figure out the details of your implementation from the W3C specification, the following is a narrative overview of how the protocol works.

Preflight Request

For any Fetch or XMLHttpRequest that modifies a resource, the browser will first send a preflight request to the server to ask if it is allowed to make this request. This will contain the Origin header containing the domain name of the requesting site, the http Method of the request in the Access-Control-Request-Method header, and any non-simple headers in the Access-Control-Request-Headers header.

The server then responds by indicating which methods, headers, and domain is permitted. Note that if you do not use Cookies, you can safely use the wildcard * value for the Access-Control-Allow-Origin header, which greatly simplifies your implementation.

OPTIONS /namespace/v1/resources/{id} HTTP/1.1
Origin: https://api.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Requested-With, Content-Type

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://api.example.com
Access-Control-Allow-Methods: PUT, GET, OPTIONS, DELETE
Access-Control-Allow-Headers: X-Requested-With, Content-Type
Access-Control-Max-Age: 86400

Main Request

For simple GET requests, or for other requests which have passed the preflight check, the client will only send the Origin header, which will contain the protocol, host, and port of the requesting site. The server will successfully execute the request, however it will inform the browser whether it’s allowed to see that data by setting the Access-Control-Allow-Origin header.

POST /namespace/v1/resources/{id} HTTP/1.1
Origin: https://api.example.com
Content-Type: application/json
X-Requested-With: XMLHttpRequest

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://api.example.com
Vary: Accept-Encoding, Origin
Content-Type: application/json

4 - Rate Limiting

Return a consistent response when a client exceeds their quota.

If your site requires some form of rate limiting, you must return a consistent response when a client exceeds their quota. This response must use the 429 status code defined in RFC 6585 Section 4, as well as the Retry-After header defined in RFC 7231 Section 7.1.3. The Retry-After header should be set to the time at which the client can retry the request, using the http-date type instead of the delta-seconds type.

For purpose of browser-level caching, the server may also include the Vary header.

HTTP/1.1 429 Too Many Requests
Retry-After: Mon, 01 Jan 2018 00:00:00 GMT
Vary: Origin, Authorization

5 - Security Headers

A variety of headers that can be added to every response to help protect your API from common web security vulnerabilities.

The following headers prevent common web security vulnerabilities. In most cases they do not themselves require any additional logic, and can be attached to every single response coming from a resource server. Functionally, they let the server inform the browser client how to protect itself from common attacks.

Strict-Transport-Security: max-age=31536000; preload

This header tells the browser that your API must be accessed via TLS/HTTPS.

X-Content-Type-Options: nosniff

This header prevents a client from attempting to sniff - and override - the content-type sent by the server.

X-Frame-Options: DENY

This header prevents an API request from being loaded in an IFrame, which is a common XSS attack vector.

X-XSS-Protection: 1; mode=block

This is a legacy header for older browsers, which you may not support. Even so, it doesn’t hurt us to add it, and it provides similar protections to Content-Security-Policy.

Referrer-Policy: no-referrer

This header controls whether a browser, while on-site, sends the Referer header when linking to another site. This kind of data is often used for user tracking, and resource servers rarely have any use for such. As such, the header returned by any Resource Server should be no-referrer.