Subsections of Consume an API
Machine-to-Machine (M2M) authentication
There are many scenarios where applications, such as CLIs, or Backend services, need to call other APIs and when these APIs requires an access token the application must be able to authenticate itself (if the call isn’t done on behalf of a user). The Client Credentials Flow (defined in OAuth 2.0) allows an application to exchange its credentials, commonly a Client ID and Client Secret for an access token.
Exchange Client Credentials for an Access Token
To exchange the client credentials for an access token the Token endpoint is used.
C# Example
In this example code IdentityModel is used to simplify the code.
Use the Access Token
After retrieving the access token it should be added in the Authrozation HTTP header on all calls to the API:
The token is typically valid for a while (in many scenarios 1 hour), so re-use the token in multiple calls instead of retrieving a new for each call. This is extra important when many calls are done, since this will otherwise cause unnecessary load on Authway.
Call an API
It is common for a system/API to need to call another API within the same organization. These APIs are often protected in the same way, requiring a Bearer token for the request to be allowed. A Bearer token is sent in the HTTP header Authorization: Authorization: Bearer [ACCESS TOKEN].
The first decision to make is what the Access Token you’re sending should represent: a user or a system. When sending a token on behalf of a user, it’s referred to as Delegation, while when the system makes the call, it follows the Trusted Subsystem pattern.
Delegation: Making a call on behalf of a user
Delegation can be handled in two different ways. One common approach is what is sometimes called “poor man’s delegation,” which involves simply sending the user’s token directly to the underlying API. The other option is for the system making the call to perform a “token exchange” (OAuth Token Exchange specification, RFC 8693).
Regardless of the chosen model, it is necessary for your web application/API to access the user’s token. To enable this, .NET needs to store the token, which is done with the following configuration code in Startup.cs:
Assuming this configuration is in place, it is possible to retrieve the user’s access token as follows:
Poor mans delegation
The biggest advantage of this variant is that it is very easy to use. The only requirement is that all the API scopes that need to be used are included when the user’s access token is created. The downside of this solution is that if this access token falls into the wrong hands, it provides access to a larger attack surface than if it only gives access to a single API scope.
Typically, for this solution, you want to add the user’s access token to the requests made via HttpClient. A good way to handle this is to create a DelegatingHandler whose task is to do this, and configure HttpClient to use it. An implementation could look like this (available in IRM.Extensions.Http):
The code above provides general support for adding a Bearer token and delegates the logic to retrieve the token itself to a class that implements IResolveBearerToken (also available in IRM.Extension.Http). For the “poor man’s delegation,” the implementation could look like this:
Token Exchange
The current version of Authway does not have complete support for Token Exchange, but it can be easily added. In conjunction with that, certain implementation details can be discussed based on the desired objectives.
Trusted Subssytem: System-to-system
To use Client Credentials, you need to configure either a regular client (Configure an Application)(../configure-authway/configure-an-application) or an external system (Configure an External System)(../configure-authway/configure-an-external-system).
OpenID Connect provides the Client Credentials flow, designed for situations where one system needs to call another system. Typically, you require a client ID and a client secret to obtain an access token using these credentials. This access token typically contains protocol-specific claims. Since it doesn’t represent a user, common claims like sub, email, name, or, in Authway’s case, perm or role, are not present. When implementing an API, significant work is required to handle this, as it differs significantly from when a user calls the API. For example, regular authorization controls don’t work, and if you want to log who made a change and save the name/ID of the person performing the change, that information is not available either. Authway supports something called External Systems to address this challenge.
External Systems are clients with support for Client Credentials. In the background, an associated user is created with the same ID (sub) as the client ID. This enables treating the calling system similarly to a user.
Example to retrieve an access token according to Client Credentials
In the same way as for a user above, we use the BearerTokenAuthenticationHandler, but with a different implementation to extract the access token. This code has dependencies on the IdentityModel NuGet package.
External system
In a basic configuration of Authway, it is still the case that an access token in the client credentials flow does not contain any user claims such as sub, name, and perm because that’s how the standard is supposed to work. There is an option to extend Authway with support that ensures these claims are included even in client credentials, but this must be done by IRM.
Instead, we recommend that the API retrieves this additional information from the Auth module when calls to the API arrive, for example, in a ClaimsTransformation class. The advantage of this approach is that the API itself can control how fresh (updated) claims it wants by managing caching, compared to when all claims are packed in the access token with the same lifespan as the token. Additionally, the token becomes smaller, and there are other advantages that you can read about in Privacy and GDPR. The same documentation also includes code examples of how to retrieve more information."
Token Exchange
OAuth 2.0 Token Exchange (available in Enterprise) allows a client to exchange a token it already has for another token that can be used to access other resources. This allows you to create tokens with narrower scope, since it enables to get another token with changed scope, different audience and it could also include a record of who is acting on whoose behalf. Important capabilites in many scenarios, for example in a micro service architecture, but almost a must have for AI Agents.
Impersonation or delegation (in the context of Token Exchange)
Impersonation is when the identity A is given all the rights that identity B has and is indistinguishable from B from the perspective of the target resource. In typical scenario where token exchange is used to get an access token, the resulting token would have the exact same content as if B got it directly in the purpose of accessing the target resource.
Delegation is when identity A still has its own identity seperate from B, but B has delegated some of its rights to A, so that actions taken by A is done representing B. This allows an audit log to prove what parties were involved in the taken action.
Here is a table showing the differences in token exchange for Impersonation and Delegation:
| Impersonation | Delegation | |
|---|---|---|
| Request | only subject_token |
subject_token and actor_token |
Issued sub |
The user | The user |
Issued act |
None | Present, identifing the client that did the exchange |
| The (API) resource sees | The user | The user and the client |
| Auditing | Only the user | The client on behalf of the user |
Scenario: AI Agent consuming a MCP Server that uses downstream API:s
In this scenario the user has identified itself to an AI Agent through Authway. The agent has recieved both an identity token and an access token. The access token is very narrow and does not include any scopes other than needed for the AI Agent itself. This is how Token Exchange with delegation is used in this scenario:
-
The agent uses the OAuth client credentials flow to get an access token representing the Agent.
-
The agent calls the Token endpoint to exchange the access token for a new access token that can be used to call the MCP Server.
- Authway will respond with an access token like this (decoded and shorted for readability):
Notice that there is an act claim identifying that it is the AI Agent that makes the call on behalf of the user identified by the sub claim.
-
The AI Agent sends the exchanged token to the MCP Server.
-
The MCP Server validates the access token as usual, making sure that it is the targeted audience for the token.
-
When the MCP Server needs to invoke the downstream API, it will start by also making a OAuth client credential request to get an access token representing the MCP Server.
-
The MCP Server calls the Token endpoint to exchange the access token for a new access token that can be used to call the downstream API.
- Authway will respond with an access token like this (decoded and shorted for readability):
Notice that there is a nestled act claim identifying that it is the MCP Server that makes the call on behalf of the user identified by the sub claim, but also information that the originating caller is the AI Agent.
- The downstream API validates the access token as usual, making sure that it is the targeted audicens for the token. It is possible for the API to log the complete chain of involved clients that have been acting on behalf of the user.
Scenario: Sharepoint or Teams plug-in needs to consume an API protected by Authway
The user is identified by Entra ID in Sharepoint or Teams and you do not want require an extra authentication by the user. In this case you can pass the Id Token that you got from the Entra sign-in, as the subject token in the token exchange.
- Get the Entra Id token. In .NET the token is recieved like this (but requires
SaveTokensset totruein OpenId Connect configuration):
- The plug-in calls the Token endpoint to exchange the id token for a new access token that can be used to call the API.
- Authway will respond with an access token like this (decoded and shorted for readability):
- The downstream API validates the access token as usual, making sure that it is the targeted audience for the token.
Pre-requisits for successful Token Exchange of Entra Id token
For the token exchange to succeed the following pre-requisits must be in place:
- The Entra tenant Id that has issued the token must be configured on at least one organisation in Authway. Authway only exchange tokens issued by configured Entra instances.
- Authway will try to find a user based on
preferred_usernameoremailclaims in the id token. If no user is found an error is returned. It is not possible to auto-provision users through token exchange. - If multiple tenants has the same Entra tenant id configured and more than one user is matched in these tenants, Authway will return the first user in a non-deterministic way, but this kind of configuration should be extremly unusual. Please contact us if this becomes an issue in your use case.
It is also important to be aware of that the external user groups is based on the state when the user signed in last time in Authway. It is not possible to get a synchronization of user groups during token exchange.
Scenario: User authenticated with a custom method
The user is identified by some mechanism that you trust, for example in an ERP system, and an extension want to call an API that is protected by Authway. We still do not want to prompt the user for another sign-in (this time in Authway), so instead the extension can create a login hint token as subject token and pass it in the token exchange (impersonation).
- The extension creates a login hint token.
- The extension calls the Token endpoint to exchange the access token for a new access token that can be used to call the API.
- Authway will respond with an access token like this (decoded and shorted for readability):
- The downstream API validates the access token as usual, making sure that it is the targeted audience for the token.