Validating JWTs with .NET
To maintain secure access to your .NET application, it's essential to validate session tokens for each request. Descope issues these session tokens as JWTs (JSON Web Tokens), which are signed and can be verified using standard .NET libraries—no need for an external SDK.
While the Descope .NET SDK provides a simple and integrated way to handle session validation, this guide walks through how to manually configure JWT validation using built-in Microsoft packages.
This guide is particularly helpful if you're already using Microsoft's JwtBearer middleware with other authentication providers and want to extend it to validate Descope JWTs.
It's also ideal for those who prefer not to use third-party SDKs and want full control over the JWT validation process by handling it manually.
Generating an OIDC-Compliant JWT
To ensure your JWTs are OAuth compliant JWT tokens, you'll need to configure an AWS API Gateway JWT template for your Descope project.
Navigate to the JWT Templates section of your Project Settings and create a new template based off of the AWS API Gateway default template:

JwtBearer Middleware (ASP.NET Core)
If you're building an ASP.NET Core application, the Microsoft.AspNetCore.Authentication.JwtBearer package is the recommended way to validate JWTs issued by Descope. You'll also need the Microsoft.IdentityModel.Tokens package to configure token validation parameters.
Install the required packages using the following commands:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.IdentityModel.TokensBasic Configuration with AddJwtBearer
For most applications, the default configuration provided by .AddJwtBearer() is sufficient. You can define your JWT settings in appsettings.json, including:
- Authority: Your Descope issuer URL (
https://api.descope.com/<Your Descope Project ID>)
You can find the Issuer URL under the Settings of your default Descope Federated Application or any other federated application you may be using with your application.
- ValidIssuer: Same as the Authority
- ValidAudiences: Your Descope Project ID
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Authentication": {
"Schemes": {
"Bearer": {
"Authority": "https://api.descope.com/<Your Descope Project ID>",
"ValidAudiences": [ "<Your Descope Project ID>" ],
"ValidIssuer": "api.descope.com/<Your Descope Project ID>"
}
}
}
}Then, enable JWT authentication in your app with the following code:
using Microsoft.AspNetCore.Authentication.JwtBearer;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication().AddJwtBearer();Advanced Configuration with TokenValidationParameters
For more granular control, you can supply custom TokenValidationParameters when configuring the JWT middleware. This is useful if you want to customize how issuer, audience, expiration, and other claims are validated.
{
"Descope": {
"Authority": "https://api.descope.com/<Your Descope Project ID>",
"Audience": "<Your Descope Project ID>"
}
}Then configure your authentication logic in code:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
string authority = builder.Configuration["Descope:Authority"];
string audience = builder.Configuration["Descope:Audience"];
builder.Services.AddAuthentication()
.AddJwtBearer("Descope", options =>
{
options.Audience = audience;
options.Authority = authority;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = authority,
ValidateAudience = true,
ValidAudiences = new[] { audience },
ValidateLifetime = true,
RequireExpirationTime = true,
ClockSkew = TimeSpan.FromMinutes(2)
};
});Token Validation in .NET Framework
If you're working in a .NET Framework environment (or another non-Core framework), you can validate JWTs using the Microsoft.IdentityModel.Tokens and Microsoft.IdentityModel.Protocols.OpenIdConnect libraries.
Install the required packages:
dotnet add package Microsoft.IdentityModel.Tokens
dotnet add package Microsoft.IdentityModel.Protocols.OpenIdConnectDefine your token settings in appsettings.json:
{
"Descope": {
"Authority": "https://api.descope.com/<Your Descope Project ID>",
"Audience": "<Your Descope Project ID>"
}
}Step 1: Fetch OIDC Signing Keys
Use Descope's OIDC discovery endpoint to retrieve the public signing keys:
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
string authority = builder.Configuration["Descope:Authority"];
string audience = builder.Configuration["Descope:Audience"];
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(
$"{authority}/.well-known/openid-configuration",
new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever());
var discoveryDocument = await configManager.GetConfigurationAsync();
var signingKeys = discoveryDocument.SigningKeys;Step 2: Validate JWTs Manually
Once you've retrieved the signing keys, you can validate a token manually:
public bool ValidateToken(
string token,
string issuer,
string audience,
ICollection<SecurityKey> signingKeys,
out JwtSecurityToken jwt
)
{
jwt = null;
var validationParams = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = issuer,
ValidateAudience = true,
ValidAudience = audience,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = signingKeys,
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(2)
};
try
{
var handler = new JwtSecurityTokenHandler();
var principal = handler.ValidateToken(token, validationParams, out SecurityToken validatedToken);
jwt = (JwtSecurityToken)validatedToken;
return true;
}
catch (SecurityTokenValidationException)
{
// Handle invalid token
return false;
}
}