A while ago, Microsoft released Identity endpoints it felt like godsend, until I realized that it wasn’t working with JWT tokens, instead, it used a different token type, and couldn’t be customized easily. This lead me to continue using JWT auth for my projects, as I used to. Then found it repetitive and I decided to build a nugget package that would make it easy and fast for you to add JWT authentication to ASP.NET Core to Your ASP.NET Core API. In this article, I’ll walk you through adding and using the package in your projects.

Installation and How to add JWT authentication to ASP.NET Core with “The.Jwt.Auth.Endpoints” nugget package

Open your ASP.net core project, and Just add the nugget package to your project (The.Jwt.Auth.Endpoints). Note, this library doesn’t support cookie auth yet! It works purely for small APIs. and is ideal for projects you’re bootstraping quickly, and you don’t want to spend time writing Auth code.

dotnet add package The.Jwt.Auth.Endpoints

You could also find the source code of the package on Github here.

Features

  • 🔐 Complete Authentication Flow: Login, registration, email confirmation, password reset
  • 🔄 JWT Token Management: Access tokens with refresh token support
  • 📧 Email Integration: Configurable email confirmation and password reset
  • 🌐 Google Social Auth: Optional Firebase Google authentication

API Endpoints

Once configured, the library provides the following endpoints:

EndpointMethodDescription
/api/auth/registerPOSTUser registration with email confirmation
/api/auth/loginPOSTUser login with email/password
/api/auth/refreshPOSTRefresh JWT access token
/api/auth/confirmEmailGETConfirm user email address
/api/auth/forgotPasswordPOSTInitiate password reset process
/api/auth/resetPasswordPOSTComplete password reset
/api/auth/social/googlePOSTGoogle Firebase authentication (optional)

 

Quick Start

1. Installation

dotnet add package The.Jwt.Auth.Endpoints

2. Basic Setup

Create Your User Model

public class ApplicationUser : IdentityUser
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? LastLoginAt { get; set; }
    public string RefreshToken { get; set; } = string.Empty;
    public DateTime RefreshTokenExpiryTime { get; set; }
    public string PictureUrl { get; set; } = string.Empty;
}

Configure Services in Program.cs

using The.Jwt.Auth.Endpoints.Extensions;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Add Entity Framework
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// Configure ASP.NET Core Identity
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.Password.RequireDigit = true;
    options.Password.RequiredLength = 8;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireUppercase = true;
    options.Password.RequireLowercase = false;

    options.User.RequireUniqueEmail = true;

    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();

// Required service implementations
builder.Services.AddScoped<IRefreshTokenRepository, RefreshTokenRepository>();
builder.Services.AddScoped<IIdentityUserFactory<ApplicationUser>, SimpleUserFactory>();
builder.Services.AddScoped<IEmailSender<ApplicationUser>, EmailSender>();

// Configure JWT Authentication
builder.Services.AddJwtAuthEndpoints<ApplicationUser>(options =>
{
    // JWT Settings
    options.JwtSettings.Secret = "your-super-secret-key-that-should-be-at-least-32-characters-long";
    options.JwtSettings.Issuer = "https://yourapp.com";
    options.JwtSettings.Audience = "YourApp";
    options.JwtSettings.TokenLifeSpanInMinutes = 60;
    options.JwtSettings.RefreshTokenLifeSpanInMinutes = 1440; // 24 hours

    // JWT Bearer Token Validation
    options.JwtAuthSchemeOptions.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = "https://yourapp.com",
        ValidAudience = "YourApp",
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your-super-secret-key-that-should-be-at-least-32-characters-long"))
    };

    // Optional: Google Firebase Auth
    options.GoogleFirebaseAuthOptions = new AppOptions()
    {
        Credential = GoogleCredential.FromFile("FirebaseServiceAccountFile.json")
    };
});

var app = builder.Build();

// Configure pipeline
app.UseAuthentication();
app.UseAuthorization();

// Map JWT authentication endpoints
app.MapJwtAuthEndpoints<ApplicationUser>();

app.Run();

3. Required Implementations

To do its job in the background, the package needs services that you’ll just have to plugin to the system. These services will tell the package how to create your users, save and retrieve refresh tokens, and send emails. So, you must provide an implementation for these.

User Factory

public class SimpleUserFactory : IIdentityUserFactory<ApplicationUser>
{
    public ApplicationUser CreateUser(string firstName, string lastName, string email, string? picture = null)
    {
        return new ApplicationUser
        {
            UserName = email,
            Email = email,
            FirstName = firstName,
            LastName = lastName,
            CreatedAt = DateTime.UtcNow,
            PictureUrl = picture ?? string.Empty
        };
    }
}

Refresh Token Repository

public class RefreshTokenRepository : IRefreshTokenRepository
{
    private readonly ApplicationDbContext _context;

    public RefreshTokenRepository(ApplicationDbContext context)
    {
        _context = context;
    }
    
    //Your implementation
}

Email Sender

public class EmailSender : IEmailSender<ApplicationUser>
{
    private readonly ILogger<EmailSender> _logger;
    private readonly IConfiguration _configuration;

    public EmailSender(ILogger<EmailSender> logger, IConfiguration configuration)
    {
        _logger = logger;
        _configuration = configuration;
    }

    public async Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink)
    {
        _logger.LogInformation("Sending confirmation email to {Email}", email);

        // TODO: Implement your email sending logic here
        // Example: using SendGrid, SMTP, or other email service

        await Task.CompletedTask;
    }

    public async Task SendPasswordResetLinkAsync(ApplicationUser user, string email, string resetLink)
    {
        _logger.LogInformation("Sending password reset email to {Email}", email);

        // TODO: Implement your password reset email logic here

        await Task.CompletedTask;
    }

    public async Task SendPasswordResetCodeAsync(ApplicationUser user, string email, string resetCode)
    {
        _logger.LogInformation("Sending password reset code to {Email}", email);

        // TODO: Implement your password reset code logic here

        await Task.CompletedTask;
    }
}

Example Usage

When you add JWT authentication to ASP.NET Core, you will need to test it. Here are the requests you can make to test your API.

Register User

POST /api/auth/register
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@example.com",
  "password": "SecurePassword123"
}

Login

POST /api/auth/login
Content-Type: application/json

{
  "email": "john.doe@example.com",
  "password": "SecurePassword123"
}

Refresh Token

POST /api/auth/refresh
Content-Type: application/json

{
  "accessToken": "your-access-token",
  "refreshToken": "your-refresh-token"
}

Forgot Password

POST /api/auth/forgotPassword
Content-Type: application/json

{
  "email": "john.doe@example.com"
}

Reset Password

POST /api/auth/resetPassword
Content-Type: application/json

{
  "email": "john.doe@example.com",
  "token": "reset-token-from-email",
  "newPassword": "NewSecurePassword123"
}

Google Social Authentication

To enable Google authentication through Firebase:

1. Configure Firebase

  1. Create a Firebase project in the Firebase Console
  2. Enable Authentication and configure Google as a sign-in provider
  3. Download the Service Account Key JSON file
  4. Place the file in your project root and set its Build Action to Content and Copy Always

2. Configure in Code

builder.Services.AddJwtAuthEndpoints<ApplicationUser>(options =>
{
    // ... other configurations

    options.GoogleFirebaseAuthOptions = new AppOptions()
    {
        Credential = GoogleCredential.FromFile("FirebaseServiceAccountFile.json")
    };
});

3. Usage

POST /api/auth/social/google
Content-Type: application/json

{
  "idToken": "firebase-id-token-from-client"
}

Configuration Options

JWT Settings

public class JwtSettings
{
    public string Secret { get; set; } = string.Empty;
    public string Issuer { get; set; } = string.Empty;
    public string Audience { get; set; } = string.Empty;
    public int TokenLifeSpanInMinutes { get; set; } = 60;
    public int RefreshTokenLifeSpanInMinutes { get; set; } = 1440;
}

Main Configuration

public class JwtAuthEndpointsConfigOptions
{
    public JwtSettings JwtSettings { get; set; } = new();
    public JwtBearerOptions JwtAuthSchemeOptions { get; set; } = new();
    public AppOptions? GoogleFirebaseAuthOptions { get; set; }
}

Security Features

  • JWT Token Validation: Comprehensive token validation with configurable parameters
  • Refresh Token Rotation: Secure refresh token implementation
  • Email Confirmation: Required email verification for new accounts
  • Password Reset: Secure password reset with time-limited tokens
  • Input Validation: Comprehensive validation using Data Annotations
  • Error Handling: Consistent error responses that don’t leak sensitive information
  • Account Lockout: Configurable account lockout after failed attempts

Testing

The library includes comprehensive integration tests. To run them:

dotnet test

Advanced Usage

Custom User Factory

Implement IIdentityUserFactory<TUser> to control user creation:

public class CustomUserFactory : IIdentityUserFactory<ApplicationUser>
{
    public ApplicationUser CreateUser(string firstName, string lastName, string email, string? picture = null)
    {
        return new ApplicationUser
        {
            UserName = email,
            Email = email,
            FirstName = firstName,
            LastName = lastName,
            CreatedAt = DateTime.UtcNow,
            PictureUrl = picture ?? string.Empty,
            // Add custom logic here
        };
    }
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

 

 

Follow me on social media and stay updated

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.