In the most basic API security use case pattern, we have one API gateway, one authorization realm, and one or more resource servers. An authorization realm is where the resource owner will authenticate and authorize the OAuth2 client to access resources on his/her behalf.
In this article, I’d like to discuss some use case patterns that build on top of this basic pattern, to have a centralized API gateway and distributed authorization realms.
Figure 1: A centralized API gateway with distributed authorization realms
This use case is commonly found in organizations due to many reasons including the operation of identity silos for many years, data governance policies or regulatory compliance that forces organizations to store user data in specific data centers or jurisdictions.
There can be three variations of this use case:
- Authorization realms can only function as authentication providers and don’t provide OAuth2 authorization server capability.
- Authorization realms can function only as OAuth2 authorization servers and don’t function as authentication providers.
- Authorization realms can function as both authentication providers and OAuth2 authorization servers.
In the first variation, where the authorization realms can only function as authentication providers, there are 2 patterns to solve it:
- Have a separate centralized OAuth2 authorization server and federate with the authentication providers for user login.
Figure 2: Centralized OAuth2 authorization server with a distributed authentication providers using federation
- Have a separate centralized OAuth2 authorization server with assertion grant flow for OAuth2, such as SAML2 Bearer Assertion grant flow or JWT Bearer grant flow.
Figure 3: Centralized API gateway with centralized OAuth2 authorization servers using assertion grant flow
The second variation, where the authorization realms can act only as OAuth2 authorization servers, is not a very common use case. This is because most OAuth2 authorization servers also provide authentication functionality at least with OpenID Connect. However, there may be certain situations where you can find this use case. For example, when you have a homegrown OAuth2 authorization server that does nothing but OAuth2; it may have been used in API management silos and now needs to move to a centralized API management solution. We generally have 2 patterns to solve this use case:
- Have a separate centralized OAuth2 authorization server with OAuth2 Redelegation grant flow that issues OAuth2 access tokens in exchange for other OAuth2 access tokens from the distributed authorization realms.
Based on the kind of OAuth2 bearer access token issued by the distributed authorization realms, we can further divide this pattern into two implementations.
- If the OAuth2 access token is a referenced token (sometimes called an opaque token), the grant handler will introspect it by calling the OAuth2 introspection endpoint of the corresponding authorization realms to validate it.
Figure 4: Centralized API gateway with centralized OAuth2 authorization servers using OAuth2 redelegation grant profile and introspection API
- If the OAuth2 access token is a self-contained access token, the grant handler will introspect and verify the authenticity of the access token by itself.
Figure 5: Centralized API gateway with centralized OAuth2 authorization servers using OAuth2 redelegation grant profile with a self-contained access token
If the self-contained access token is in the format of a JWT, the “aud” attribute of the JWT can be used to express the centralized authorization server as an intended audience for the access token.
In both solutions above, we can introduce a new scope in the distributed authorization servers in order to authorize the access token and exchange it with a new access token in the centralized authorization server. This will
provide an additional layer of consent.
However, a point to note is that in this pattern we are violating the confidentiality principle of the bearer access token (for confidential clients). The access token should be known only between the client and the authorization server. Even though the gateway, which is in the same trust domain as the authorization server, will have access to the access token during API invocation, it shouldn’t unintentionally or deliberately make use of it in a way that could compromise the confidentiality of the access token.
In this pattern, the access token from the distributed authorization realm is sent to the centralized authorization server that has been introduced. If both authorization servers belong to one trust domain, which is mostly the case, then this pattern is perfect. However, if they don’t belong to one trusted domain, this pattern violates the basic principle of confidentiality of the bearer access token.
To overcome this problem there could be several custom solutions you can come up with. The following solution is one of the simplest solutions you can implement.
The access token generated from the distributed authorization server can have two separate parts. For example, the access token may be a Base64 encoded String of the following JSON structure:
The token_id can be considered as a reference token to the authorization grant at the distributed authorization server, which means that the first part in isolation can be used as a credential to prove the authorization grant at the distributed authorization server. However, it cannot be used in isolation to access APIs protected directly by the distributed authorization server. Now the token_id can be sent to the centralized authorization server to be exchanged for a new access token. In this case, the OAuth2 client has some additional work to do.
- Integrate the API gateway to all the authorization realms using APIs.
Figure 6: Centralized API gateway with distributed OAuth2 authorization servers using API integration
In the third variation of the us case, we can actually select one of the above solution patterns from variations 1 and 2, by carefully evaluating the pros and cons of each solution pattern. In general, however, API integration between the centralized API Gateway and distributed authorization servers is discouraged.
Although there are standards such OAuth2 introspection and User-Managed Access (UMA) resource set registration to standardize communication between the API gateway and OAuth2 authorization server, as of now, not all standards have been widely adopted at the same level in the industry. Most vendors only support these standards partially and require integration using proprietary APIs. In such cases, integration becomes complex and the integration code in the gateway gets coupled to the proprietary APIs of the authorization server. If each of the authorization servers is from a different vendor, then it will be more costly and complex to write and manage all this integration code.
In the solution patterns we’ve discussed above, we’ve introduced you to the “Federated Authorization Realm” pattern. This is where the OAuth2 authorization server federates with another authorization realm, and both servers in combination are responsible for the authentication of the resource owner and the delegation of authorization to the OAuth2 client.
So far we’ve looked at use cases where the authorization realms were distributed by user realms, but still, the resource servers were not distributed by user realms. We will now look at how the above API Security patterns can be extended to have distributed resource servers by user realms. As with the identity data, the business data in the resource servers may also need to satisfy data governance policies or regulatory compliance which forces the organization to store data in specific data centers or jurisdictions.
Figure 7: Centralized OAuth2 authorization server with distributed authentication providers using federation and distributed resource servers
In order to support this pattern, in addition to what we’ve discussed in the federated login pattern in the previous use case, we also need the capability to dynamically route the API request to the appropriate backend resource server based on the authorization realm the user has authorized from. To transport this piece of information from the authorization realm to the API Gateway, we will use the following features:
- In the response from the authentication providers we will return the authentication realm identifier as an attribute. How the attribute returned will depend on the authentication protocol used between the centralized OAuth2 authorization server and the authentication providers, and on the business use case of how the realms are split and identified.
- To transport this piece of information from the centralized OAuth2 authorization server, and make it available during the API call received at the API gateway, we will use the “Self-contained OAuth2 Access Token” pattern. That is, we will generate the access token by embedding the realm information into it so that it can be introspected at the API gateway and the resource server to route to will be dynamically decided.
For example, the access token may be a Base64 encoded String of the following JSON structure:
In this article we’ve looked at some interesting API security use case patterns around distributed authorization realms. The list of patterns in this article is by no means exhaustive. There certainly can be more use case patterns that we are yet to establish. However while dealing with new kinds of use cases, you may be able to draw similarities to the use case patterns we’ve discussed so far. This would help you better analyze the new use cases, document it as use case pattern, build a common vocabulary around it, and evangelize it as a pattern that will solve common enterprise IAM needs.
The use case patterns discussed in this article are patterns that we have repeatedly encountered over the years while working with multiple global corporations. We have now perfected implementing them using WSO2 Identity Server and WSO2 API Manager.