Using Descope JWTs with Azure API Management
By configuring Descope JWTs to work with Azure API Management (APIM), you can protect your backend APIs using secure, validated tokens issued by Descope. This allows you to enforce fine-grained access control and identity verification before traffic reaches your API endpoints.
Azure APIM offers a built-in policy called validate-jwt
that you can use to decode and validate JWTs issued by trusted identity providers like Descope.
Requirements
- A Descope project with JWT templates configured.
- An Azure API Management instance.
- An API published in your APIM instance.
Step 1: Configure a JWT Template in Descope
Go to the JWT Template section of the Descope Console and select the AWS API Gateway template.
This changes the iss
claim from just the Project ID to a fully qualified URL, such as "iss": "https://api.descope.com/P2PqjhPcC8Hri2nXUY7f234F"
.
Step 2: Apply validate-jwt
Policy in APIM
In Azure API Management (APIM), policies are a way to control how requests and responses are processed through your APIs. You can apply policies at different levels depending on your needs:
- Product level: A product is a collection of APIs bundled together (e.g., all internal APIs, all partner APIs). When you apply a policy at the product level, it applies to all APIs and operations in that product.
- API level: An API in APIM is a logical wrapper for a backend service. Applying a policy at the API level applies it to all operations (routes) within that API.
- Operation level: An operation is a single endpoint, such as
GET /orders
orPOST /users
. Applying a policy at this level only affects that specific route.
If you want to apply JWT validation across all endpoints of an API, use the API level. If you need more granular control (e.g., only protect POST
endpoints), apply the policy at the operation level.
How to Apply the validate-jwt
Policy
To validate Descope JWTs at the operation level, follow these steps:
- Navigate to your Azure API Management instance in the Azure portal.
- In the left-hand menu, go to APIs and select the API you want to protect.
- From the API design view, select a specific operation (e.g.,
GET /users
) or click on the API name to apply the policy to all operations. - Go to the Design tab, then select Inbound processing.
- Click Add policy, then choose Validate JWT from the policy templates.
- You can now paste the policy below, or use the policy editor to configure the policy.
Here's a sample validate-jwt
policy:
Replace <YourProjectID>
with your actual Descope project ID.
Note
If you are using a custom domain, or in a region outside of the US, your openid-config
URL will be different. You can find this under the Discovery URL section of your default federated OIDC application.
Once added, this policy will:
- Look for a
Bearer
token in theAuthorization
header. - Use the OpenID configuration from Descope to verify the JWT signature.
- Ensure the
aud
(audience) claim matches your Descope project ID. - Reject requests with missing or invalid tokens by returning a
401 Unauthorized
response.
This setup allows APIM to handle JWT validation directly at the gateway, reducing the need to repeat validation logic in each backend service.
Note
All OIDC-compliant JWTs created with Descope have an aud
claim that matches the project ID.
If you're create JWTs with a custom audience claim, add the other audience claim to the validate-jwt
policy as well.
Step 3: Test with a Descope JWT
- Authenticate a user with Descope and retrieve their JWT.
- Make an API call to your APIM-protected endpoint, including the JWT in the
Authorization
header:
If the token is valid, the request will be allowed through. Otherwise, APIM will return a 401 Unauthorized
response.
Optional: Enforce Roles or Scopes
You can add custom claims to your Descope JWT (e.g., role
, scope
) and enforce them using the <claim>
tags in the validate-jwt
policy.
Handling Authorization Claims in Descope JWTs
By default, Descope JWTs use a nested tenants
object to define roles and permissions per tenant. However, Azure API Management's validate-jwt
policy does not currently support evaluating nested JSON structures, which means you cannot validate roles that are nested within the tenants
object.
To validate roles effectively, you can use a different authorization claim format in your JWT template.
If you use the Current tenant, no tenant reference authorization claim format in your JWT template, roles
will exist in the JWT at directly at the top level (e.g., project-wide roles or tenant-scoped roles with dct
), and therefore can be validated using your validate-jwt
policy.
This is an example of a JWT with flat roles:
With this format, you can enforce access by matching the role or permission directly:
You can configure this custom authorization structure via your JWT Template settings, in the Authorization Claims section.
Step 3: Consuming JWT Output in the Backend
Once validate-jwt
is configured, you can forward validated token data to your backend by using the output-token-variable-name
parameter and setting a custom header with the token contents.
Using Custom Headers to Forward the JWT
This sets a header called Descope-Token
with the entire validated JWT object as a JSON object.
Note
Use hyphenated header names like Descope-Token
, as underscores or spaces are not supported.
Conditionally Add Custom Headers If Token Is Present
If you only want to set the header if the token is present, you can use the condition
attribute to check if the token is present.
This ensures the header is only set when token validation is successful.
Adding Specific Claims from the JWT to Custom Headers
Note
The sub
claim is the subject of the JWT, which is the Descope user ID.
If your services need to access specific claims from the JWT, rather than the entire JWT, you can extract them and forward them as custom headers.
This will set the Descope-Subject
and Descope-Email
headers with the sub
and email
claims from the JWT.
Creating a Reusable JWT Validation Fragment
Azure API Management (APIM) policies are often repeated across different APIs or endpoints — for example, validating a JWT and extracting claims might be needed in multiple places.
Rather than copying and pasting the same policy logic into every API or operation, APIM lets you define a reusable block of policy code called a policy fragment.
Example Fragment
You create a fragment called ValidateJwtFragment
that includes:
- A
validate-jwt
policy to check the Descope token. - A few
set-header
policies to forward user claims likeemail
andsub
.
Then, in any API, you just include the fragment like this:
This automatically applies all the validation and header logic — without needing to repeat it every time.
Once defined, you can include the fragment at the inbound policy section:
This modular approach keeps your JWT validation logic consistent and reusable across multiple APIs or operations.
Conclusion
Using Descope JWTs with Azure API Management enables you to enforce identity-based access control directly at the API gateway layer.
By applying a few policy configurations in APIM and issuing structured JWTs from Descope, you can manage access to your APIs without adding custom authentication logic to your backend services.
For more information on how to configure Azure API Management policies in general, see the Azure API Management policies documentation.