Skip to content

anassrh/Secure-Backend-API-with-ASP.NET-Core

Repository files navigation

SecureHexagonalApi

A production-oriented ASP.NET Core REST API demonstrating Clean / Hexagonal Architecture, JWT authentication with refresh token rotation, role & permission-based authorization, and maintainable backend engineering practices.

Built as a portfolio project to showcase backend skills beyond a simple CRUD API.


Overview

SecureHexagonalApi is a secure user-management API where business rules live in the Domain and Application layers, while HTTP, persistence, and security implementations stay in the outer layers.

The API focuses on:

  • Strong separation of concerns (Domain / Application / Infrastructure / API)
  • Secure authentication and session management
  • Input validation and consistent error responses
  • Audit logging for sensitive operations
  • Unit tests on application use cases

This is intentionally clear and explainable in an interview, while still reflecting real-world backend patterns.


Key Features

  • JWT authentication with short-lived access tokens
  • Refresh tokens with rotation and anti-replay protection
  • Access token revocation via JWT blacklist (logout)
  • Role & permission-based authorization (HasPermission attribute)
  • Active session management per user
  • API versioning (v1 / v2)
  • FluentValidation on request DTOs
  • Centralized error handling with RFC 7807 ProblemDetails
  • Audit logging for write operations
  • Health check endpoint (/health)
  • Swagger / OpenAPI with Bearer JWT support
  • Unit tests for core Application handlers

Architecture

The solution follows Clean / Hexagonal Architecture:

┌──────────────────────────────────────────────┐
│                    API                       │
│  Controllers, DTOs, Middleware, Swagger      │
└──────────────────────┬───────────────────────┘
                       │
┌──────────────────────▼───────────────────────┐
│               Application                    │
│  Use cases (Handlers), Ports, DTOs           │
└──────────────────────┬───────────────────────┘
                       │
┌──────────────────────▼───────────────────────┐
│                  Domain                        │
│  Entities, Value Objects, Business Rules       │
└──────────────────────┬───────────────────────┘
                       │
┌──────────────────────▼───────────────────────┐
│             Infrastructure                   │
│  EF Core, Repositories, JWT, Audit Logger    │
└──────────────────────────────────────────────┘

Dependency rule: inner layers never depend on outer layers.
The Application layer defines ports (interfaces); Infrastructure provides adapters.


Tech Stack

Layer Technologies
API ASP.NET Core 8, Swagger, API Versioning
Application Handlers (use cases), FluentValidation
Domain Entities, Value Objects, Domain Exceptions
Infrastructure Entity Framework Core, SQL Server, BCrypt, JWT
Tests xUnit

Security Features

  • Password hashing with BCrypt
  • JWT signed with HMAC-SHA256
  • Refresh token rotation on every refresh request
  • Revoked refresh tokens cannot be reused
  • Access tokens can be blacklisted on logout
  • Permission-based authorization at endpoint level
  • No secrets committed in source code (configuration-driven)
  • Request validation before reaching application logic

Authentication Flow

1. POST /api/v1/auth/login
   └─> Returns access token + refresh token

2. Authenticated requests
   └─> Authorization: Bearer {access_token}

3. POST /api/v1/auth/refresh
   └─> Sends refresh token
   └─> Old refresh token is revoked
   └─> New access token + new refresh token are returned

4. POST /api/v1/auth/logout
   └─> Refresh token revoked
   └─> Current access token JTI added to blacklist

5. POST /api/v1/auth/logout-all
   └─> All refresh tokens revoked for the user

Session metadata (IP address, user agent) is stored with refresh tokens to support session inspection.


Project Structure

SecureHexagonalApi/
├── SecureHexagonalApi.API/           # HTTP layer (controllers, DTOs, middleware)
├── SecureHexagonalApi.Application/   # Use cases, ports, application DTOs
├── SecureHexagonalApi.Domain/        # Core business model
├── SecureHexagonalApi.Infrastructure/# EF Core, repositories, JWT, audit
└── SecureHexagonalApi.Tests/         # Unit tests (Application & Domain)

API Versioning

Versioning is URL-based:

  • api/v1/... — stable endpoints
  • api/v2/... — evolved response format (e.g. wrapped API responses on login)

Swagger exposes a document per API version.


Error Handling with ProblemDetails

Unhandled exceptions are converted to RFC 7807 ProblemDetails:

Scenario HTTP Status Response
FluentValidation failure 400 ValidationProblemDetails
Business rule violation 400 / 401 / 404 ProblemDetails
Unexpected server error 500 ProblemDetails

Example:

{
  "title": "Validation error",
  "status": 400,
  "errors": {
    "Email": ["Invalid email format."]
  }
}

Validation with FluentValidation

Request DTOs are validated at the API boundary:

  • LoginRequest
  • RefreshTokenRequest
  • LogoutRequest
  • CreateUserRequest
  • UpdateUserRequest
  • AssignRoleRequest
  • AssignPermissionRequest

Controllers stay thin and delegate business logic to Application handlers.


Audit Logging

Sensitive write operations (user creation, role assignment, etc.) are logged through IAuditLogger.

Audit logs can be queried via the protected audit endpoints (requires audit.read permission).


Unit Tests

Tests focus on Application handlers with fake repositories and services:

  • AuthenticateUserHandlerTests
  • RefreshTokenHandlerTests
  • CreateUserHandlerTests
  • Auth session / logout handler tests
  • Domain value object tests (Email)

Run tests:

dotnet test

Getting Started

Prerequisites

Clone the repository

git clone https://github.com/anassrh/SecureHexagonalApi.git
cd SecureHexagonalApi
cp SecureHexagonalApi.API/appsettings.Development.example.json SecureHexagonalApi.API/appsettings.Development.json

Environment Variables

Configuration is loaded from appsettings.json, appsettings.Development.json, and environment variables.

Key Description
ConnectionStrings__DefaultConnection SQL Server connection string
Jwt__Secret JWT signing secret (min. 32 characters)
Jwt__AccessTokenExpirationMinutes Access token lifetime (default: 30)
Jwt__RefreshTokenExpirationDays Refresh token lifetime (default: 7)
Seed__AdminEmail Default admin email for seeding
Seed__AdminPassword Default admin password for seeding

Never commit production secrets. Use User Secrets locally or environment variables in deployment.

Local development (User Secrets example)

cd SecureHexagonalApi.API
dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=(localdb)\\mssqllocaldb;Database=SecureHexagonalApiDb;Trusted_Connection=True;TrustServerCertificate=True"
dotnet user-secrets set "Jwt:Secret" "your-local-secret-key-at-least-32-chars"

Run the Project

dotnet restore
dotnet ef database update --project SecureHexagonalApi.Infrastructure --startup-project SecureHexagonalApi.API
dotnet run --project SecureHexagonalApi.API

Then open:

  • Swagger UI: https://localhost:{port}/swagger
  • Health check: https://localhost:{port}/health

Default seeded admin (Development):

  • Email: admin@localhost
  • Password: Admin123!

Run Tests

dotnet test

Roadmap

  • Integration tests with WebApplicationFactory
  • Rate limiting on auth endpoints
  • Structured logging with Serilog
  • Docker Compose (API + SQL Server)
  • CI/CD pipeline (GitHub Actions)
  • Redis-backed token blacklist for distributed deployments

Author

Anass Rhouzladi


License

This project is available for portfolio and learning purposes.

About

Secure ASP.NET Core Web API using Clean/Hexagonal Architecture, JWT authentication, refresh tokens, role-based authorization, EF Core, FluentValidation and unit tests.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages