## ASP.NET Core backend protection Control access to your backend using ASP.NET Core Web API. When your routes receive API calls, ASP.NET Core Web API checks the caller's identity and grants access only if the caller is authorized to access the route. ### Step-by-step guide Follow the steps below to validate tokens using ASP.NET Core Web API. ### Step 1: Install dependency To get started with ASP.NET Core token validation, you first need to install the required dependency. ``` Install-Package Microsoft.AspNetCore.Authentication.JwtBearer ``` ### Step 2: Configure startup 1. In the **Frontegg portal**, navigate to [ENVIRONMENT] ➜ Configurations ➜ Keys & Domains. 2. From the **General** tab, copy your client ID and from the **Domains** tab, copy your Frontegg domain. 3. Next, configure your authentication middleware in your `Startup.cs` file. Enter your workspace name and client ID into the code sample below, replacing the placeholders. ``` // Startup.cs public void ConfigureServices(IServiceCollection services) { // ... // ... string domain = "https://[YOUR-FRONTEGG-DOMAIN].frontegg.com"; // Put your Frontegg domain name instead of [YOUR-FRONTEGG-DOMAIN] services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = domain; options.Audience = "[my-client-id]" // Put your client ID instead of [my-client-id] // If the access token does not have a `sub` claim, `User.Identity.Name` will be `null`. Map it to a different claim by setting the NameClaimType below. options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = ClaimTypes.NameIdentifier }; }); } ``` br To add the authentication and authorization middleware to the middleware pipeline, add a call to the `UseAuthentication` and `UseAuthorization` hooks in your `Startup.cs` file. ``` // Startup.cs public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // ... // ... app.UseAuthentication(); app.UseAuthorization(); // ... // ... } ``` ## Step 3: Validate roles Next, you need to validate that the token has the required roles claims. Create a new authorization checker called `HasRoleRequirement`. This validator checks if the roles claim issued by your Frontegg workspace is present. If the roles claim exists, the validator checks if the roles claim contains the requested role. ``` // HasRoleRequirement.cs public class HasRoleRequirement : IAuthorizationRequirement { public string Issuer { get; } public string Role { get; } public HasRoleRequirement(string role) { Role = role ?? throw new ArgumentNullException(nameof(role)); Issuer = issuer ?? throw new ArgumentNullException(nameof(issuer)); } } ``` br ``` // HasRoleHandler.cs public class HasRoleHandler : AuthorizationHandler { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasRoleRequirement requirement) { // If user does not have the scope claim, get out of here if (!context.User.HasClaim(c => c.Type == "roles" && c.Issuer == requirement.Issuer)) return Task.CompletedTask; // Split the roles string into an array var roles = context.User.FindFirst(c => c.Type == "roles" && c.Issuer == requirement.Issuer).Value.Split(' '); // Succeed if the roles array contains the required role if (roles.Any(s => s == requirement.Role)) context.Succeed(requirement); return Task.CompletedTask; } } ``` br On the Startup's `ConfigureServices` method, add a call to the `AddAuthorization` method. To add policies for the roles, call `AddPolicy` for each role. One more thing: ensure that you register the `HasRoleHandler` as a singleton: ``` // Startup.cs public void ConfigureServices(IServiceCollection services) { //... services.AddAuthorization(options => { options.AddPolicy("admin", policy => policy.Requirements.Add(new HasRoleRequirement("admin", domain))); }); services.AddSingleton(); //... } ``` br The usage of the authorization protection on your web API endpoints is as simple as the below: ``` // Controllers/ApiController.cs [Route("api")] public class ApiController : Controller { [HttpGet("admin-scoped")] [Authorize("admin")] public IActionResult Scoped() { return Ok(new { Message = "Hello from a private admin endpoint! You need to be authenticated and have a role of admin to see this." }); } } ```