Implementing Zero Trust APIs

Implementing Zero Trust APIs

On this page

This article provides an application-focused summary of the main best practices Curity recommends, to integrate zero trust OAuth security into your APIs. If you are new to OAuth, see also the IAM primer, to understand the main components you will need. This article drills a little deeper into API behaviors, to provide a blueprint for your next generation API security.

Start with JWT Access Tokens

Firstly, every API or microservice must receive and validate a JWT access token, on every request for secured resources. Validate both calls from internet clients and also calls from internal clients within the backend cluster. The code required is straightforward, and there are examples for many API technologies in API Guides.

Validating JWTs

When related microservices call each other, the JWT can usually be simply forwarded, as a token sharing technique. This securely maintains the user identity for upstream microservices, which in turn enables them to perform user level authorization and auditing. The pattern can also be extended to asynchronous communication between APIs, as detailed in zero trust API events.

Centralize Trust

Some example code to validate a JWT access token is shown in this code snippet, for a Node.js API. Only the authorization server can produce the JWT, which is then verified using public key cryptography. This makes it very difficult for malicious parties to call your APIs, and is much more secure than trusting values in unverifiable HTTP headers.

const jwksEndpoint = 'https://login.example.com/.well-known/jwks';
const remoteJWKSet = createRemoteJWKSet(new URL(jwksEndpoint), jwksOptions);

function validateJwtAccessToken(accessToken) {

    const options = {
        algorithms: ['RS256'],
        issuer: 'https://login.example.com',
        audience: 'api.example.com',
    };
    const result = await jwtVerify(accessToken, this._jwksRetriever.remoteJWKSet, options);
    const claims = result.payload;
    return claims;
}

The API connects to the JSON Web Keyset (JWKS) endpoint of the authorization server, to download token signing public keys, which are then cached. Use of an authorization server and a JWT library provides a key management solution. The more subtle point is that this URL expresses who the API trusts, which is only the authorization server. This is the central source of trust for your applications.

Secure Internet Credentials

Although JWT access tokens work well for APIs, they are simply base64-encoded JSON, and easily readable, so they should not be returned to internet clients. To prevent information disclosure, issue opaque, unreadable access tokens to internet clients. For browser based apps, also follow the current best practice of using secure HTTP-only cookies. This results in the following end-to-end application flow, for APIs with web and mobile clients:

Application flow

Use API Gateway Hosting

An API gateway or reverse proxy should provide the internet URLs for your APIs. This is a hosting security best practice, but also gives you great options for separating concerns. The plumbing to translate from opaque access tokens or cookies to JWTs can then be handled via utility plugins that run within the gateway. See the Phantom Token and Token Handler patterns for how this works. Managing these concerns in the gateway keeps the security code in your APIs simple and business focused.

Use Claims Based Authorization

After the JWT access token is validated, use scopes and claims to perform authorization checks. Each API has its own expected scopes, and will only accept access tokens that contain them. You therefore need to design scopes when forwarding access tokens between microservices. See the Scope Best Practices article for a complete description of scopes.

The deeper behavior is your Object Level Authorization, which ensures that your business data is accessed correctly. Scopes are fixed at design time, whereas claims are calculated at runtime. In some systems you will need to include values from your business data, so your authorization server needs to support this. The Claims Best Practices article describes how to manage claims.

Meet API Compliance and Regulatory Standards

The JWT access token represents a digital identity that remains verifiable, which has auditing benefits. This architecture also gives you other tools for managing compliance issues, so that you can avoid dealing with these concerns in your API code. This could include managing Privacy and GDPR in the authorization server, or using Dynamic User Routing in the API gateway, to ensure that data sovereignty restrictions are satisfied.

Add Infrastructure Security

Modern hosting platforms provide you with additional tools for managing security in backend clusters, which can be used in addition to OAuth security. Mutual TLS connections can be used between components, such as an API and its database, to ensure that internal connections are authenticated. Access can be restricted further via role based security and network policies.

Infrastructure security alone is insufficient to protect your backend platform though. APIs should always implement their own security, and avoid trusting claims in headers received from a gateway or sidecar. By doing so, you receive a verifiable user identity for calls that originated outside the cluster. You also enable your APIs to call each other using token sharing techniques, and act as OAuth clients when required.

Conclusion

Curity recommends using the above ingredients in your API architecture, to protect your business data in an end-to-end manner. The patterns described, and the separation of concerns, are scalable to many APIs and clients, and require only simple code.