askill
dotnet-api-auth

dotnet-api-authSafety 85Repository

Authentication and authorization patterns for ASP.NET Core Web APIs

0 stars
1.2k downloads
Updated 2/5/2026

Package Files

Loading files...
SKILL.md

.NET API Authentication Skill

Patterns and implementations for securing ASP.NET Core Web APIs with authentication and authorization.

JWT Bearer Authentication

Configure JWT Bearer authentication in Program.cs:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
        };
    });

// Add after building the app
app.UseAuthentication();
app.UseAuthorization();

Required appsettings.json configuration:

{
  "Jwt": {
    "Key": "your-256-bit-secret-key-here-min-32-chars",
    "Issuer": "https://yourdomain.com",
    "Audience": "https://yourdomain.com"
  }
}

API Key Authentication

Custom middleware for API key validation:

public class ApiKeyMiddleware
{
    private const string ApiKeyHeaderName = "X-API-Key";
    private readonly RequestDelegate _next;

    public ApiKeyMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context, IConfiguration config)
    {
        if (!context.Request.Headers.TryGetValue(ApiKeyHeaderName, out var extractedApiKey))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("API Key is missing");
            return;
        }

        var apiKey = config["ApiKey"];
        if (!apiKey.Equals(extractedApiKey))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Invalid API Key");
            return;
        }

        await _next(context);
    }
}

// Register in Program.cs
app.UseMiddleware<ApiKeyMiddleware>();

Policy-Based Authorization

Define and register authorization policies:

builder.Services.AddAuthorizationBuilder()
    .AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"))
    .AddPolicy("PremiumUser", policy => policy.RequireClaim("Subscription", "Premium"))
    .AddPolicy("MinimumAge", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(18)));

// Register custom handlers
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();

Apply policies to endpoints:

[Authorize(Policy = "AdminOnly")]
[HttpDelete("{id}")]
public IActionResult Delete(int id) { /* ... */ }

// Or with minimal APIs
app.MapDelete("/admin/users/{id}", () => Results.Ok())
    .RequireAuthorization("AdminOnly");

Claims and Roles

Access claims in controllers:

[Authorize]
[HttpGet("profile")]
public IActionResult GetProfile()
{
    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    var email = User.FindFirst(ClaimTypes.Email)?.Value;
    var roles = User.FindAll(ClaimTypes.Role).Select(c => c.Value);

    return Ok(new { userId, email, roles });
}

// Check roles
if (User.IsInRole("Admin"))
{
    // Admin-specific logic
}

Generate tokens with claims:

public string GenerateToken(User user)
{
    var claims = new List<Claim>
    {
        new(ClaimTypes.NameIdentifier, user.Id.ToString()),
        new(ClaimTypes.Email, user.Email),
        new(ClaimTypes.Role, user.Role),
        new("CustomClaim", "CustomValue")
    };

    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
    var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

    var token = new JwtSecurityToken(
        issuer: _config["Jwt:Issuer"],
        audience: _config["Jwt:Audience"],
        claims: claims,
        expires: DateTime.UtcNow.AddHours(1),
        signingCredentials: credentials);

    return new JwtSecurityTokenHandler().WriteToken(token);
}

Resource-Based Authorization

Authorize access to specific resources:

public class DocumentAuthorizationHandler :
    AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        OperationAuthorizationRequirement requirement,
        Document resource)
    {
        var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;

        if (requirement.Name == Operations.Read.Name && resource.OwnerId == userId)
        {
            context.Succeed(requirement);
        }

        if (requirement.Name == Operations.Update.Name &&
            (resource.OwnerId == userId || context.User.IsInRole("Admin")))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

Use in a controller:

public class DocumentsController : ControllerBase
{
    private readonly IAuthorizationService _authService;

    [HttpGet("{id}")]
    public async Task<IActionResult> Get(int id)
    {
        var document = await _repository.GetAsync(id);
        var result = await _authService.AuthorizeAsync(User, document, Operations.Read);

        if (!result.Succeeded)
            return Forbid();

        return Ok(document);
    }
}

CORS Configuration

Configure CORS for API access:

builder.Services.AddCors(options =>
{
    // Named policy for specific origins
    options.AddPolicy("AllowSpecificOrigin", policy =>
    {
        policy.WithOrigins("https://example.com", "https://app.example.com")
              .AllowAnyMethod()
              .AllowAnyHeader()
              .AllowCredentials();
    });

    // Development policy (more permissive)
    options.AddPolicy("Development", policy =>
    {
        policy.AllowAnyOrigin()
              .AllowAnyMethod()
              .AllowAnyHeader();
    });
});

// Apply globally
app.UseCors("AllowSpecificOrigin");

// Or per-endpoint
app.MapGet("/api/public", () => "Hello")
    .RequireCors("AllowSpecificOrigin");

Quick Reference

PatternUse CaseKey Components
JWT BearerToken-based authAddJwtBearer, TokenValidationParameters
API KeySimple service authCustom middleware, header validation
Policy-BasedRole/claim requirementsAddPolicy, [Authorize(Policy)]
Resource-BasedPer-resource permissionsIAuthorizationService, custom handlers
CORSCross-origin requestsAddCors, UseCors

Additional Resources

  • See examples/jwt-setup-example.cs for complete JWT configuration
  • See examples/policy-auth-example.cs for custom authorization requirements

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

94/100Analyzed 2/11/2026

An excellent technical reference for .NET security patterns. It provides clear, actionable code snippets for multiple authentication and authorization strategies, including JWT, API keys, and resource-based logic, along with configuration examples.

85
95
100
95
95

Metadata

Licenseunknown
Version-
Updated2/5/2026
Publishermajiayu000

Tags

apisecurity