Skip to content

Consume internal API on behalf of an employeeΒΆ

This how-to guides you through the steps required to consume an API secured with Entra ID on behalf of an employee. This is also known as the on-behalf-of (OBO) flow.

PrerequisitesΒΆ

Configure your applicationΒΆ

Depending on how you communicate with the API you're consuming, configure the appropriate outbound access policies.

Use webproxy for outbound network connectivity from on-premises environments

If you're on-premises, you must enable and use webproxy to access Entra ID.

Exchange tokenΒΆ

Now you can exchange the employees subject token for a new token targeting the API that you want to consume.

To exchange a token, you can either:

Exchange tokens with TexasΒΆ

Texas is not enabled by default

See the Texas documentation for more information.

Send a HTTP POST request to the endpoint found in the NAIS_TOKEN_EXCHANGE_ENDPOINT environment variable. The request must have a Content-Type header set to either:

  • application/json or
  • application/x-www-form-urlencoded

The body of the request should contain the following parameters:

Parameter Example Value Description
identity_provider azuread Always azuread.
target api://<cluster>.<namespace>.<other-api-app-name>/.default The intended audience (target API or recipient) of the new token.
user_token eyJra... The user's access token from the inbound request. Token that should be exchanged.
Token request
POST ${NAIS_TOKEN_EXCHANGE_ENDPOINT} HTTP/1.1
Content-Type: application/json

{
    "identity_provider": "azuread",
    "target": "api://<cluster>.<namespace>.<other-api-app-name>/.default",
    "user_token": "eyJra..."
}
Token request
POST ${NAIS_TOKEN_EXCHANGE_ENDPOINT} HTTP/1.1
Content-Type: application/x-www-form-urlencoded

identity_provider=azuread&
target=api://<cluster>.<namespace>.<other-api-app-name>/.default&
user_token=eyJra...
Successful response
{
    "access_token": "eyJra...",
    "expires_in": 3599,
    "token_type": "Bearer"
}

Your application does not need to validate this token.

Tokens are cached by default with regards to the expires_in field. To forcibly fetch a new token, set the skip_cache=true parameter in the request.

Exchange tokens manuallyΒΆ

The token request is an HTTP POST request. It must have the Content-Type header set to application/x-www-form-urlencoded.

The body of the request should contain the following parameters:

Parameter Example Value Description
assertion eyJraWQ... The employee's subject token from the inbound request. Token that should be exchanged.
client_id 60dea49a-255b-48b5-b0c0-0974ac1c0b53 Client identifier for your application. Set to the AZURE_APP_CLIENT_ID environment variable.
client_secret <some-secret> Client secret for your application. Set to the AZURE_APP_CLIENT_SECRET environment variable.
grant_type urn:ietf:params:oauth:grant-type:jwt-bearer Always urn:ietf:params:oauth:grant-type:jwt-bearer.
requested_token_use on_behalf_of Always on_behalf_of.
scope api://<cluster>.<namespace>.<other-api-app-name>/.default The intended audience (target API or recipient) of the new token.

Send the request to the token_endpoint, i.e. the URL found in the AZURE_OPENID_CONFIG_TOKEN_ENDPOINT environment variable:

Token request
POST ${AZURE_OPENID_CONFIG_TOKEN_ENDPOINT} HTTP/1.1
Content-Type: application/x-www-form-urlencoded

assertion=<subject_token>&
client_id=${AZURE_APP_CLIENT_ID}&
client_secret=${AZURE_APP_CLIENT_SECRET}&
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&
requested_token_use=on_behalf_of&
scope=api://<cluster>.<namespace>.<other-api-app-name>/.default
Successful response
{
  "access_token" : "eyJ0eX[...]",
  "expires_in" : 3599,
  ...
}

Your application does not need to validate this token.

Token Caching

The expires_in field denotes the lifetime of the token in seconds.

Cache and reuse the token until it expires to minimize network latency impact.

A safe cache key for this flow is key = sha256($subject_token + $scope).

Consume APIΒΆ

Once you have acquired a new token, you can finally consume the target API by using the token as a Bearer token:

GET /resource HTTP/1.1

Host: api.example.com
Authorization: Bearer eyJraWQ...

πŸ“š Entra ID reference