Skip to main content
ClaudeWave
Skill68 repo starsupdated 14d ago

dotnet-jwt-authentication

This Claude Code skill configures JWT Bearer authentication for .NET APIs with token generation, validation, and refresh token management. Use it when building secure REST APIs that need access tokens for stateless authentication, refresh tokens stored in HttpOnly cookies for enhanced security, and automatic user context extraction from JWT claims for authorization purposes.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/ronnythedev/dotnet-clean-architecture-skills /tmp/dotnet-jwt-authentication && cp -r /tmp/dotnet-jwt-authentication/skills/12-dotnet-jwt-authentication ~/.claude/skills/dotnet-jwt-authentication
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# JWT Authentication Setup

## Overview

This skill implements JWT (JSON Web Token) authentication for .NET APIs:

- **Access Token** - Short-lived JWT returned in response body
- **Refresh Token** - Stored in HttpOnly cookie (secure, not accessible via JavaScript)
- **Options Pattern** - Configurable expiration via JwtOptions
- **Token Rotation** - New refresh token issued on each refresh
- **Security Audit** - Comprehensive event tracking for compliance
- **Token generation** - Create access and refresh tokens
- **Token validation** - Validate incoming tokens
- **User context** - Extract user info from claims

## Quick Reference

| Component | Purpose | Location |
|-----------|---------|----------|
| `IJwtService` | Token generation interface | Application/Abstractions |
| `JwtService` | Token generation implementation | Infrastructure/Authentication |
| `JwtOptions` | configuration (expiration, issuer, etc.) | Infrastructure/Authentication |
| `JwtBearerOptionsSetup` | Configure JWT validation | Infrastructure/Authentication |
| `IUserContext` | Current user info | Application/Abstractions |
| `UserContext` | Extract from HttpContext | Infrastructure/Authentication |
| `IRefreshTokenRepository` | Refresh token storage | Domain/Identity |
| `CookieSettings` | Cookie configuration | Infrastructure/Authentication |

---

## Authentication Structure

```
/Application/Abstractions/
├── Authentication/
│   ├── IJwtService.cs
│   ├── IUserContext.cs
│   ├── TokenResponse.cs
│   └── AuthenticationErrors.cs

/Infrastructure/
├── Authentication/
│   ├── JwtOptions.cs
│   ├── JwtService.cs
│   ├── JwtBearerOptionsSetup.cs
│   ├── UserContext.cs
│   ├── CookieSettings.cs
│   └── RefreshTokenCookieManager.cs
```

---

## Template: JWT Configuration Options

```csharp
// src/{name}.infrastructure/Authentication/JwtOptions.cs
namespace {name}.infrastructure.authentication;

public sealed class JwtOptions
{
    public const string SectionName = "Jwt";

    public string Issuer { get; init; } = string.Empty;
    public string Audience { get; init; } = string.Empty;
    public string SecretKey { get; init; } = string.Empty;
    public int AccessTokenExpirationMinutes { get; init; } = 60;
    public int RefreshTokenExpirationDays { get; init; } = 7;
    public CookieSettings Cookie { get; init; } = new();
}

public sealed class CookieSettings
{
    /// <summary>
    /// Name of the refresh token cookie
    /// </summary>
    public string Name { get; init; } = "X-Refresh-Token";

    /// <summary>
    /// Cookie domain (leave empty for current domain)
    /// </summary>
    public string? Domain { get; init; }

    /// <summary>
    /// Cookie path
    /// </summary>
    public string Path { get; init; } = "/api/v1/auth";

    /// <summary>
    /// SameSite policy (Strict recommended for healthcare)
    /// </summary>
    public SameSiteMode SameSite { get; init; } = SameSiteMode.Strict;

    /// <summary>
    /// Require HTTPS (always true in production)
    /// </summary>
    public bool SecureOnly { get; init; } = true;
}
```

### appsettings.json

```json
{
  "Jwt": {
    "Issuer": "your-app-name",
    "Audience": "your-app-name",
    "SecretKey": "your-secret-key-at-least-32-characters-long-for-security",
    "AccessTokenExpirationMinutes": 60,
    "RefreshTokenExpirationDays": 7,
    "Cookie": {
      "Name": "X-Refresh-Token",
      "Domain": "",
      "Path": "/api/v1/auth",
      "SameSite": "Strict",
      "SecureOnly": true
    }    
  }
}
```

---

## Template: JWT Service Interface

```csharp
// src/{name}.application/Abstractions/Authentication/IJwtService.cs
using {name}.domain.users;

namespace {name}.application.abstractions.authentication;

public interface IJwtService
{
    /// <summary>
    /// Generate access and refresh tokens for a user
    /// </summary>
    TokenGenerationResult GenerateTokens(
        User user, 
        IEnumerable<string> roles,
        IEnumerable<string>? permissions = null);

    /// <summary>
    /// Generate tokens with custom claims
    /// </summary>
    TokenGenerationResult GenerateTokens(
        Guid userId,
        string email,
        IEnumerable<string> roles,
        IDictionary<string, string>? additionalClaims = null);

    /// <summary>
    /// Hash a refresh token for secure database storage
    /// </summary>
    string HashRefreshToken(string refreshToken);

    /// <summary>
    /// Verify a plain refresh token against its hash
    /// </summary>
    bool VerifyRefreshToken(string plainToken, string hashedToken);

    /// <summary>
    /// Get access token expiration time
    /// </summary>
    DateTime GetAccessTokenExpiry();

    /// <summary>
    /// Get refresh token expiration time
    /// </summary>
    DateTime GetRefreshTokenExpiry();
}
```

---

## Template: Token Response

```csharp
// src/{name}.application/Abstractions/Authentication/TokenResponse.cs
namespace {name}.application.abstractions.authentication;

/// <summary>
/// Response containing access token (refresh token is set via HttpOnly cookie)
/// </summary>
public sealed record TokenResponse(
    string AccessToken,
    DateTime AccessTokenExpiration,
    string TokenType = "Bearer");

/// <summary>
/// Internal response including refresh token (for cookie setting)
/// </summary>
public sealed record TokenGenerationResult(
    string AccessToken,
    string RefreshToken,
    DateTime AccessTokenExpiration,
    DateTime RefreshTokenExpiration);
```

---

## Template: JWT Service Implementation

```csharp
// src/{name}.infrastructure/Authentication/JwtService.cs
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using {name}.application.Abstractions.Authentication;
using {name}.application.Abstractions.Clock;
using {name}.domain.identity;

namespace {name}.infrastructure.authentication;

internal sealed class JwtService : I
dotnet-clean-architectureSkill

Scaffolds a complete .NET solution following Clean Architecture principles with proper layer separation (API, Application, Domain, Infrastructure). Creates project structure, dependency injection setup, and cross-cutting concerns configuration.

dotnet-cqrs-command-generatorSkill

Generates CQRS Commands with Handlers, Validators, and Request DTOs following Clean Architecture patterns. Commands represent actions that modify state and return Result types for proper error handling.

dotnet-cqrs-query-generatorSkill

Generates CQRS Queries with Handlers and Response DTOs for read operations. Uses Dapper for optimized read queries, bypassing the domain model for better performance.

dotnet-domain-entity-generatorSkill

Generates Domain Entities following DDD principles with factory methods, private setters, domain events, and proper encapsulation. Supports aggregate roots, child entities, and value objects.

dotnet-repository-patternSkill

Generates Repository interfaces and implementations following the Repository pattern. Provides data access abstraction for aggregate roots with EF Core implementations.

dotnet-ef-core-configurationSkill

Generates Entity Framework Core configurations using Fluent API. Maps domain entities to database tables with proper relationships, constraints, and conventions.

dotnet-legacy-api-controllersSkill

Generates RESTful API Controllers with proper routing, versioning, authorization, and MediatR integration. Follows REST conventions and Clean Architecture patterns.

dotnet-minimal-api-endpointsSkill

Generates Minimal API endpoints following Microsoft's recommended approach. Creates fast, testable HTTP APIs with minimal code using MapGet/MapPost/MapPut/MapDelete. Preferred over controller-based APIs for new projects.