Documentation Index Fetch the complete documentation index at: https://mintlify.com/IntentArchitect/Intent.Modules.NET/llms.txt
Use this file to discover all available pages before exploring further.
The Intent.Security.JWT module configures JWT (JSON Web Token) Bearer authentication for your ASP.NET Core Web APIs, providing a complete token-based security infrastructure.
Overview
This module sets up JWT Bearer authentication middleware, configures token validation parameters, and integrates with the application’s security infrastructure. It provides the foundation for stateless, token-based API authentication.
What Gets Generated
JWT Configuration
Configures JWT Bearer authentication in your application:
public static class JwtConfiguration
{
public static IServiceCollection AddJwtAuthentication (
this IServiceCollection services ,
IConfiguration configuration )
{
var jwtSettings = configuration . GetSection ( "JwtSettings" ). Get < JwtSettings >();
services . AddAuthentication ( options =>
{
options . DefaultAuthenticateScheme = JwtBearerDefaults . AuthenticationScheme ;
options . DefaultChallengeScheme = JwtBearerDefaults . AuthenticationScheme ;
})
. AddJwtBearer ( options =>
{
options . RequireHttpsMetadata = true ;
options . SaveToken = true ;
options . TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true ,
ValidateAudience = true ,
ValidateLifetime = true ,
ValidateIssuerSigningKey = true ,
ValidIssuer = jwtSettings . Issuer ,
ValidAudience = jwtSettings . Audience ,
IssuerSigningKey = new SymmetricSecurityKey (
Encoding . UTF8 . GetBytes ( jwtSettings . Secret )),
ClockSkew = TimeSpan . Zero
};
options . Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if ( context . Exception is SecurityTokenExpiredException )
{
context . Response . Headers . Add ( "Token-Expired" , "true" );
}
return Task . CompletedTask ;
},
OnChallenge = context =>
{
context . HandleResponse ();
context . Response . StatusCode = StatusCodes . Status401Unauthorized ;
context . Response . ContentType = "application/json" ;
var result = JsonSerializer . Serialize ( new
{
error = "You are not authorized"
});
return context . Response . WriteAsync ( result );
}
};
});
return services ;
}
}
Current User Service
Provides access to the authenticated user:
public interface ICurrentUserService
{
Guid ? UserId { get ; }
string ? UserName { get ; }
string ? Email { get ; }
bool IsAuthenticated { get ; }
bool IsInRole ( string role );
bool HasClaim ( string claimType , string claimValue );
}
public class CurrentUserService : ICurrentUserService
{
private readonly IHttpContextAccessor _httpContextAccessor ;
public CurrentUserService ( IHttpContextAccessor httpContextAccessor )
{
_httpContextAccessor = httpContextAccessor ;
}
public Guid ? UserId
{
get
{
var userIdClaim = _httpContextAccessor . HttpContext ? . User
. FindFirstValue ( ClaimTypes . NameIdentifier );
return Guid . TryParse ( userIdClaim , out var userId ) ? userId : null ;
}
}
public string ? UserName =>
_httpContextAccessor . HttpContext ? . User ? . Identity ? . Name ;
public string ? Email =>
_httpContextAccessor . HttpContext ? . User
? . FindFirstValue ( ClaimTypes . Email );
public bool IsAuthenticated =>
_httpContextAccessor . HttpContext ? . User ? . Identity ? . IsAuthenticated ?? false ;
public bool IsInRole ( string role ) =>
_httpContextAccessor . HttpContext ? . User ? . IsInRole ( role ) ?? false ;
public bool HasClaim ( string claimType , string claimValue ) =>
_httpContextAccessor . HttpContext ? . User
? . HasClaim ( claimType , claimValue ) ?? false ;
}
Key Features
Bearer Authentication Standard JWT Bearer token validation
Claims-Based Access user identity and claims
Stateless No server-side session storage required
Flexible Authorization Support for roles, policies, and claims
Module Settings
JWT Bearer Authentication Type
JWT Bearer Authentication Type
Configure how JWT tokens are authenticated Options:
oidc - OpenID Connect JWT authentication (recommended)
manual - Manual JWT authentication with custom validation
Configuration
appsettings.json
Configure JWT settings:
{
"JwtSettings" : {
"Secret" : "your-256-bit-secret-key-here-minimum-32-characters" ,
"Issuer" : "https://yourdomain.com" ,
"Audience" : "https://yourdomain.com" ,
"ExpiryInMinutes" : 60
}
}
Environment Variables
For production, use environment variables or Azure Key Vault:
export JwtSettings__Secret = "production-secret-key"
export JwtSettings__Issuer = "https://api.production.com"
export JwtSettings__Audience = "https://api.production.com"
Authorization Strategies
Role-Based Authorization
Authorize based on user roles:
[ Authorize ( Roles = "Admin" )]
[ HttpDelete ( "{id}" )]
public async Task < ActionResult > Delete (
[ FromRoute ] Guid id ,
CancellationToken cancellationToken )
{
await _service . DeleteAsync ( id , cancellationToken );
return NoContent ();
}
// Multiple roles (OR logic)
[ Authorize ( Roles = "Admin,Manager" )]
[ HttpGet ( "reports" )]
public async Task < ActionResult < List < ReportDto >>> GetReports ()
{
// User must be in Admin OR Manager role
}
Policy-Based Authorization
Define custom authorization policies:
// In Program.cs or Startup
services . AddAuthorization ( options =>
{
options . AddPolicy ( "RequireAdminRole" , policy =>
policy . RequireRole ( "Admin" ));
options . AddPolicy ( "RequireManagerOrHigher" , policy =>
policy . RequireRole ( "Admin" , "Manager" ));
options . AddPolicy ( "RequireEditPermission" , policy =>
policy . RequireClaim ( "Permission" , "Edit" ));
options . AddPolicy ( "RequireAgeOver18" , policy =>
policy . Requirements . Add ( new MinimumAgeRequirement ( 18 )));
options . AddPolicy ( "RequireAdminAndVerified" , policy =>
{
policy . RequireRole ( "Admin" );
policy . RequireClaim ( "Verified" , "true" );
});
});
Use policies in controllers:
[ Authorize ( Policy = "RequireEditPermission" )]
[ HttpPut ( "{id}" )]
public async Task < ActionResult > Update (
[ FromRoute ] Guid id ,
[ FromBody ] UpdateDto dto ,
CancellationToken cancellationToken )
{
await _service . UpdateAsync ( id , dto , cancellationToken );
return NoContent ();
}
Custom Authorization Handlers
Implement custom authorization logic:
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public int MinimumAge { get ; }
public MinimumAgeRequirement ( int minimumAge )
{
MinimumAge = minimumAge ;
}
}
public class MinimumAgeHandler : AuthorizationHandler < MinimumAgeRequirement >
{
protected override Task HandleRequirementAsync (
AuthorizationHandlerContext context ,
MinimumAgeRequirement requirement )
{
var dateOfBirthClaim = context . User . FindFirst (
c => c . Type == "DateOfBirth" );
if ( dateOfBirthClaim == null )
{
return Task . CompletedTask ;
}
var dateOfBirth = DateTime . Parse ( dateOfBirthClaim . Value );
var age = DateTime . Today . Year - dateOfBirth . Year ;
if ( dateOfBirth . Date > DateTime . Today . AddYears ( - age ))
{
age -- ;
}
if ( age >= requirement . MinimumAge )
{
context . Succeed ( requirement );
}
return Task . CompletedTask ;
}
}
// Register the handler
services . AddScoped < IAuthorizationHandler , MinimumAgeHandler >();
Claims-Based Authorization
Authorize based on specific claims:
[ Authorize ]
[ HttpGet ( "my-data" )]
public async Task < ActionResult < UserDataDto >> GetMyData ()
{
var userId = User . FindFirstValue ( ClaimTypes . NameIdentifier );
var email = User . FindFirstValue ( ClaimTypes . Email );
var roles = User . FindAll ( ClaimTypes . Role ). Select ( c => c . Value ). ToList ();
// Custom claims
var department = User . FindFirstValue ( "Department" );
var employeeId = User . FindFirstValue ( "EmployeeId" );
return Ok ( new UserDataDto
{
UserId = Guid . Parse ( userId ),
Email = email ,
Roles = roles ,
Department = department ,
EmployeeId = employeeId
});
}
Token Validation
The module configures comprehensive token validation:
Validation Parameters
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true , // Validate token issuer
ValidateAudience = true , // Validate token audience
ValidateLifetime = true , // Check token expiration
ValidateIssuerSigningKey = true , // Validate signing key
ValidIssuer = jwtSettings . Issuer ,
ValidAudience = jwtSettings . Audience ,
IssuerSigningKey = new SymmetricSecurityKey (
Encoding . UTF8 . GetBytes ( jwtSettings . Secret )),
ClockSkew = TimeSpan . Zero // No tolerance for expired tokens
};
Custom Validation
Add custom token validation:
options . Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
var userService = context . HttpContext . RequestServices
. GetRequiredService < IUserService >();
var userId = context . Principal . FindFirstValue ( ClaimTypes . NameIdentifier );
// Check if user still exists and is active
var user = userService . GetByIdAsync ( Guid . Parse ( userId )). Result ;
if ( user == null || ! user . IsActive )
{
context . Fail ( "User is no longer active" );
}
return Task . CompletedTask ;
},
OnAuthenticationFailed = context =>
{
if ( context . Exception is SecurityTokenExpiredException )
{
context . Response . Headers . Add ( "Token-Expired" , "true" );
}
return Task . CompletedTask ;
}
};
Protecting Endpoints
Controller Level
Protect entire controller:
[ Authorize ]
[ ApiController ]
[ Route ( "api/orders" )]
public class OrdersController : ControllerBase
{
// All endpoints require authentication
[ AllowAnonymous ] // Except this one
[ HttpGet ( "public" )]
public ActionResult < List < OrderDto >> GetPublicOrders ()
{
// Public endpoint
}
}
Action Level
Protect specific actions:
[ ApiController ]
[ Route ( "api/products" )]
public class ProductsController : ControllerBase
{
[ HttpGet ] // Public
public ActionResult < List < ProductDto >> GetAll ()
{
// Anyone can view products
}
[ Authorize ] // Protected
[ HttpPost ]
public ActionResult < Guid > Create ([ FromBody ] CreateProductDto dto )
{
// Requires authentication
}
[ Authorize ( Roles = "Admin" )] // Admin only
[ HttpDelete ( "{id}" )]
public ActionResult Delete ([ FromRoute ] Guid id )
{
// Only admins can delete
}
}
Using Current User Service
Access current user information in your services:
public class OrderService : IOrderService
{
private readonly IApplicationDbContext _dbContext ;
private readonly ICurrentUserService _currentUserService ;
public OrderService (
IApplicationDbContext dbContext ,
ICurrentUserService currentUserService )
{
_dbContext = dbContext ;
_currentUserService = currentUserService ;
}
public async Task < Guid > CreateOrderAsync (
CreateOrderDto dto ,
CancellationToken cancellationToken )
{
if ( ! _currentUserService . IsAuthenticated )
throw new UnauthorizedException ( "User must be authenticated" );
var order = new Order
{
CustomerId = _currentUserService . UserId . Value ,
CustomerEmail = _currentUserService . Email ,
CreatedBy = _currentUserService . UserName ,
// ... other properties
};
_dbContext . Orders . Add ( order );
await _dbContext . SaveChangesAsync ( cancellationToken );
return order . Id ;
}
public async Task < List < OrderDto >> GetMyOrdersAsync (
CancellationToken cancellationToken )
{
var userId = _currentUserService . UserId . Value ;
return await _dbContext . Orders
. Where ( x => x . CustomerId == userId )
. ProjectToListAsync < OrderDto >( _mapper . ConfigurationProvider , cancellationToken );
}
}
Error Handling
Unauthorized (401)
Returned when:
No token provided
Invalid token
Expired token
Token signature doesn’t match
options . Events = new JwtBearerEvents
{
OnChallenge = context =>
{
context . HandleResponse ();
context . Response . StatusCode = 401 ;
context . Response . ContentType = "application/json" ;
var result = JsonSerializer . Serialize ( new
{
error = "Unauthorized" ,
message = "You must be authenticated to access this resource"
});
return context . Response . WriteAsync ( result );
}
};
Forbidden (403)
Returned when:
User is authenticated but lacks required permissions
Missing required role
Authorization policy not met
services . AddAuthorization ( options =>
{
options . FallbackPolicy = new AuthorizationPolicyBuilder ()
. RequireAuthenticatedUser ()
. Build ();
});
Security Best Practices
Use a strong secret key (minimum 256 bits / 32 characters)
Store secrets in Azure Key Vault or AWS Secrets Manager
Never commit secrets to source control
Use different secrets for each environment
Rotate keys periodically
Keep access tokens short-lived (15-60 minutes)
Use refresh tokens for longer sessions
Set ClockSkew to zero for strict expiration
Implement token revocation for critical operations
Always use HTTPS in production
Set RequireHttpsMetadata to true
Enable HSTS (HTTP Strict Transport Security)
Use secure cookie flags
Validate all claims on the server
Don’t trust client-provided data
Implement additional validation in TokenValidated event
Check user status (active/disabled) on sensitive operations
OpenID Connect (OIDC) Authentication
When using OIDC mode:
services . AddAuthentication ( JwtBearerDefaults . AuthenticationScheme )
. AddJwtBearer ( options =>
{
options . Authority = "https://your-identity-provider.com" ;
options . Audience = "your-api-audience" ;
options . RequireHttpsMetadata = true ;
options . TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true ,
ValidateAudience = true ,
ValidateLifetime = true ,
ValidateIssuerSigningKey = true
};
});
Installation
Dependencies
Intent.Application.Identity (>= 3.6.0)
Intent.AspNetCore (>= 6.0.3)
Intent.Common.CSharp
Intent.OutputManager.RoslynWeaver
Integration
Automatically integrates with:
Intent.IdentityServer4.SecureTokenServer - For IdentityServer4
Intent.AspNetCore.Swashbuckle - Adds auth UI to Swagger
Intent.AspNetCore.Identity - For user management
Next Steps
Identity Add user management with ASP.NET Core Identity
Identity JWT Combine Identity with JWT authentication
Swashbuckle Add JWT auth to Swagger UI
Controllers Protect your API endpoints