NAuth is a complete, modular authentication framework designed for fast and secure user management in modern web applications. Built using .NET 8, React, Bootstrap, and PostgreSQL, NAuth provides a robust solution for user registration, login, password recovery, and profile updates β ready to be integrated into any full-stack project.
The project follows a clean architecture approach with separated layers for API, Application, Domain, Infrastructure, ACL (Anti-Corruption Layer), DTOs, and comprehensive test coverage.
- π User Registration - Complete registration flow with email confirmation
- π JWT Authentication - Secure token-based authentication
- π Password Recovery - Secure password reset via email with token validation
- βοΈ Profile Management - User profile update and password change
- π₯ Role-Based Access Control - User roles and permissions management
- π§ Email Integration - Email templates and SMTP support
- ποΈ PostgreSQL Database - Schema and migrations included
- π¦ Modular Architecture - Reusable across multiple projects
- π REST API - Complete RESTful API with Swagger documentation
- π³ Docker Support - Production-ready Docker configurations
- β Health Checks - Built-in health check endpoints
- π Security - Non-root containers, encrypted passwords, token validation
- .NET 8.0 - Modern, cross-platform framework for building web APIs
- ASP.NET Core - Web framework for building HTTP services
- Entity Framework Core 9.0.8 - ORM with proxy support
- PostgreSQL - Robust relational database
- Npgsql.EntityFrameworkCore.PostgreSQL 9.0.8 - PostgreSQL provider for EF Core
- JWT (JSON Web Tokens) - Secure authentication mechanism
- PBKDF2/BCrypt - Strong password hashing algorithms
- Token-based Email Verification - Secure email confirmation and password reset
- React - Modern UI library
- Bootstrap - Responsive UI components
- React Hooks - Custom authentication hooks
- Swashbuckle.AspNetCore 9.0.4 - Swagger/OpenAPI documentation
- MailerSend Integration - Email delivery service
- xUnit - Unit testing framework
- Comprehensive test coverage across all layers
- Docker - Containerization with multi-stage builds
- Docker Compose - Multi-container orchestration
- GitHub Actions - CI/CD pipeline
NAuth.API/
βββ NAuth.API/ # Web API layer with controllers
β βββ Controllers/ # API endpoints (User, Role, etc.)
β βββ appsettings.*.json # Configuration files
β βββ Startup.cs # Application configuration
βββ NAuth.Application/ # Application layer with DI setup
β βββ Initializer.cs # Dependency injection configuration
βββ NAuth.Domain/ # Domain layer with business logic
β βββ Models/ # Domain models
β βββ Services/ # Business logic services
β βββ Factory/ # Domain factories
β βββ LocalAuthHandler.cs # Local authentication handler
βββ NAuth.Infra/ # Infrastructure layer
β βββ Context/ # Database context
β βββ Repository/ # Data access repositories
βββ NAuth.Infra.Interfaces/ # Repository interfaces
βββ NAuth.Test/ # Comprehensive test suite
β βββ Domain/ # Domain tests
β βββ Infra/ # Infrastructure tests
β βββ ACL/ # ACL tests
βββ Dockerfile # Production-ready Docker image
βββ docker-compose.yml # Docker Compose configuration
βββ postgres.Dockerfile # PostgreSQL container
βββ README.md # This file
- NAuth.DTO - Data Transfer Objects (NuGet package)
- NAuth.ACL - Anti-Corruption Layer (NuGet package)
- NAuth.APP - Frontend React application
- NAuth.React - React component library (npm package)
Before running the application, you need to configure the environment variables:
cp .env.example .env# PostgreSQL Database Configuration
POSTGRES_DB=nauth_db
POSTGRES_USER=nauth
POSTGRES_PASSWORD=your_secure_password_here_change_this
POSTGRES_PORT=5432
# Connection String
# Use 'nauth-postgres' when running with Docker Compose
CONNECTION_STRING=Host=nauth-postgres;Port=5432;Database=nauth_db;Username=nauth;Password=your_secure_password_here_change_this
# JWT Configuration (minimum 64 characters)
JWT_SECRET=your_jwt_secret_with_at_least_64_characters_for_maximum_security_change_this_value
# NAuth API Configuration
API_HTTP_PORT=5004
API_HTTPS_PORT=5005
CERTIFICATE_PASSWORD=your_certificate_password_here- Never commit the
.envfile with real credentials - Only the
.env.exampleshould be version controlled - Change all default passwords and secrets before deployment
- JWT_SECRET must be at least 64 characters for security
docker network create emagine-networkOr remove the external: true configuration from docker-compose.yml if you don't need an external network.
docker-compose up -d --buildThis command will:
- Build the Docker images for both API and PostgreSQL
- Create and start the containers
- Set up networking between containers
- Apply health checks
Check container status:
docker-compose psView logs:
# All services
docker-compose logs -f
# API only
docker-compose logs -f nauth-api
# PostgreSQL only
docker-compose logs -f postgresAfter deployment, the services will be available at:
- Frontend App: http://localhost:5006
- API HTTP: http://localhost:5004
- API HTTPS: https://localhost:5005
- Swagger UI: http://localhost:5004/swagger
- Health Check: http://localhost:5004/ (returns JSON with application status)
- PostgreSQL: localhost:5432 (accessible from host machine)
| Action | Command |
|---|---|
| Start services | docker-compose up -d |
| Start with rebuild | docker-compose up -d --build |
| Stop services | docker-compose stop |
| Restart services | docker-compose restart |
| View status | docker-compose ps |
| View all logs | docker-compose logs -f |
| View API logs | docker-compose logs -f nauth-api |
| View DB logs | docker-compose logs -f postgres |
| Remove containers | docker-compose down |
| Remove containers and volumes ( |
docker-compose down -v |
For production environments, use the production configuration:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --buildThe production configuration includes:
- Resource limits and reservations
- Rolling update strategy
- Enhanced security settings
- Optimized logging
- Health check configurations
- .NET 8.0 SDK
- PostgreSQL 12+
- Node.js 16+ (for frontend)
Create a PostgreSQL database and update the connection string in NAuth.API/appsettings.Development.json:
{
"ConnectionStrings": {
"NAuthContext": "Host=localhost;Port=5432;Database=nauth_db;Username=nauth;Password=your_password"
}
}Update JWT configuration in NAuth.API/appsettings.Development.json:
{
"NAuth": {
"JwtSecret": "your_jwt_secret_at_least_64_characters_long"
}
}cd NAuth.Infra
dotnet ef database update --startup-project ../NAuth.APIcd NAuth.API
dotnet restore
dotnet runThe API will be available at:
- HTTP: http://localhost:5004
- HTTPS: https://localhost:5005
- Swagger: http://localhost:5004/swagger
cd Frontend/nauth-app
npm installUpdate the API URL in your frontend configuration to point to your backend.
npm startWhen making changes to the Frontend/nauth-core library:
cd Frontend/nauth-app
npm install --legacy-peer-deps ../nauth-coreThe NAuth API provides comprehensive endpoints for user authentication and management.
1. Register β 2. Verify Email β 3. Login β 4. Access Protected Resources
Manages user registration, authentication, and profile operations.
POST /User/register
Register a new user account.
- Request Body:
UserInfoobject{ "name": "John Doe", "email": "john@example.com", "password": "SecurePassword123!", "cpf": "12345678900", "phone": "5511999999999" } - Returns:
200 OK- User registered successfully (returns user ID)400 Bad Request- Validation errors500 Internal Server Error- Registration failed
- Notes:
- Sends verification email to user
- Password is hashed before storage
- CPF is validated
POST /User/login
Authenticate user and receive JWT token.
- Request Body:
LoginParamobject{ "email": "john@example.com", "password": "SecurePassword123!" } - Returns:
200 OK- Returns JWT token and user info{ "token": "eyJhbGciOiJIUzI1NiIs...", "user": { "id": 1, "name": "John Doe", "email": "john@example.com", "roles": ["User"] }, "expiresAt": "2024-01-16T10:00:00Z" }401 Unauthorized- Invalid credentials500 Internal Server Error- Login failed
POST /User/verifyEmail
Verify user email with token.
- Request Body:
EmailVerificationParamobject{ "userId": 1, "token": "verification-token-from-email" } - Returns:
200 OK- Email verified successfully400 Bad Request- Invalid or expired token500 Internal Server Error- Verification failed
POST /User/requestPasswordReset
Request password reset token.
- Request Body:
{ "email": "john@example.com" } - Returns:
200 OK- Reset email sent404 Not Found- User not found500 Internal Server Error- Request failed
- Notes: Sends password reset email with token
POST /User/resetPassword
Reset password with token.
- Request Body:
PasswordResetParamobject{ "email": "john@example.com", "token": "reset-token-from-email", "newPassword": "NewSecurePassword123!" } - Returns:
200 OK- Password reset successfully400 Bad Request- Invalid or expired token500 Internal Server Error- Reset failed
PUT /User/{id}
Update user profile.
- Parameters:
id(int, path): User ID
- Request Body:
UserInfoobject (partial update supported) - Returns:
200 OK- User updated successfully401 Unauthorized- Not authenticated403 Forbidden- Not authorized to update this user404 Not Found- User not found500 Internal Server Error- Update failed
- Authorization: Requires JWT token
GET /User/{id}
Get user profile by ID.
- Parameters:
id(int, path): User ID
- Returns:
200 OK- Returns user profile401 Unauthorized- Not authenticated404 Not Found- User not found
- Authorization: Requires JWT token
GET /User/email/{email}
Get user by email address.
- Parameters:
email(string, path): User email
- Returns:
200 OK- Returns user profile401 Unauthorized- Not authenticated404 Not Found- User not found
- Authorization: Requires JWT token
POST /User/changePassword
Change user password.
- Request Body:
ChangePasswordParamobject{ "userId": 1, "currentPassword": "OldPassword123!", "newPassword": "NewSecurePassword123!" } - Returns:
200 OK- Password changed successfully401 Unauthorized- Not authenticated or invalid current password500 Internal Server Error- Change failed
- Authorization: Requires JWT token
Manages user roles and permissions.
GET /Role/list
Get all available roles.
- Returns:
200 OK- Array of role objects[ { "id": 1, "name": "Admin", "description": "Administrator role" }, { "id": 2, "name": "User", "description": "Standard user role" } ]401 Unauthorized- Not authenticated
- Authorization: Requires JWT token
POST /Role/assignRole
Assign a role to a user.
- Request Body:
UserRoleParamobject{ "userId": 1, "roleId": 2 } - Returns:
200 OK- Role assigned successfully401 Unauthorized- Not authenticated403 Forbidden- Not authorized404 Not Found- User or role not found500 Internal Server Error- Assignment failed
- Authorization: Requires JWT token with admin role
DELETE /Role/removeRole/{userId}/{roleId}
Remove a role from a user.
- Parameters:
userId(int, path): User IDroleId(int, path): Role ID
- Returns:
200 OK- Role removed successfully401 Unauthorized- Not authenticated403 Forbidden- Not authorized404 Not Found- User role assignment not found500 Internal Server Error- Removal failed
- Authorization: Requires JWT token with admin role
GET /
Application health check endpoint.
- Returns:
200 OK- Application is healthy{ "currentTime": "2024-01-15 10:30:00", "statusApplication": "Healthy" }503 Service Unavailable- Application is unhealthy
- JWT Tokens - Secure, stateless authentication
- Token Expiration - Configurable token lifetime
- Refresh Tokens - Support for token refresh (configurable)
- Strong Hashing - PBKDF2 or BCrypt algorithms
- Salt - Unique salt for each password
- Password Validation - Minimum complexity requirements
- Password Reset - Secure token-based flow with expiration
- Token-based Verification - Secure email confirmation
- Token Expiration - Tokens expire after configured time
- One-time Use - Tokens are invalidated after use
- Configurable Origins - Control allowed origins
- Secure Headers - Proper CORS headers
- Credentials Support - Optional credential support
- Non-root User - Containers run as non-root user (
appuser) - Security Capabilities - Minimal capabilities assigned
- Read-only Filesystem - Where possible
- Secret Management - Environment-based secrets
- Parameterized Queries - Protection against SQL injection
- Connection Encryption - SSL/TLS support
- User Isolation - Separate database users for different operations
Manual Backup:
docker exec nauth-postgres pg_dump -U nauth nauth_db > backup_$(date +%Y%m%d_%H%M%S).sqlCompressed Backup:
docker exec nauth-postgres pg_dump -U nauth nauth_db | gzip > backup_$(date +%Y%m%d_%H%M%S).sql.gzManual Restore:
docker exec -i nauth-postgres psql -U nauth -d nauth_db < backup_20240115_120000.sqlRestore Compressed Backup:
gunzip < backup_20240115_120000.sql.gz | docker exec -i nauth-postgres psql -U nauth -d nauth_dbFor production, set up automated backups using cron (Linux/Mac):
# Add to crontab (crontab -e)
0 2 * * * cd /path/to/nauth && docker exec nauth-postgres pg_dump -U nauth nauth_db > backup_$(date +\%Y\%m\%d_\%H\%M\%S).sqlOr Windows Task Scheduler:
# Create scheduled task
schtasks /create /tn "NAuth Backup" /tr "docker exec nauth-postgres pg_dump -U nauth nauth_db > C:\backups\nauth\backup_%date:~-4,4%%date:~-10,2%%date:~-7,2%.sql" /sc daily /st 02:00The project includes comprehensive test coverage across all layers.
All Tests:
dotnet testSpecific Project:
dotnet test NAuth.Test/NAuth.Test.csprojWith Coverage:
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencoverNAuth.Test/
βββ Domain/
β βββ Models/ # Domain model tests
β βββ Services/ # Business logic tests
β βββ LocalAuthHandlerTests.cs
βββ Infra/
β βββ Repository/ # Data access tests
βββ ACL/
βββ UserClientTests.cs
βββ RoleClientTests.cs
βββ RemoteAuthHandlerTests.cs
Check logs:
docker-compose logs nauth-apiCommon causes:
- Database connection failed (check CONNECTION_STRING)
- Port already in use (change API_HTTP_PORT in .env)
- Missing environment variables (check .env file)
Verify PostgreSQL is running:
docker-compose ps postgresCheck PostgreSQL logs:
docker-compose logs postgresTest connection:
docker exec nauth-postgres pg_isready -U nauth -d nauth_dbCommon solutions:
- Wait for PostgreSQL to fully start (check health status)
- Verify CONNECTION_STRING uses correct host (
nauth-postgresfor Docker) - Check POSTGRES_PASSWORD matches in .env and CONNECTION_STRING
Test health endpoint:
curl http://localhost:5000/Check application logs:
docker-compose logs nauth-apiFind process using port:
# Linux/Mac
lsof -i :5000
# Windows
netstat -ano | findstr :5000Solution:
- Kill the process using the port
- Or change port in .env file:
API_HTTP_PORT=6000 API_HTTPS_PORT=6001
Symptoms:
- HTTPS not working
- Certificate errors in logs
Solutions:
- Verify
NAuth.API/emagine.pfxexists - Check CERTIFICATE_PASSWORD in .env
- For development, use HTTP only (port 5000)
Clear Docker cache:
docker-compose build --no-cacheCheck disk space:
docker system dfClean up Docker:
docker system prune -af- Check logs:
docker-compose logs -f - Check container status:
docker-compose ps - Open an issue: GitHub Issues
Connect to NAuth API from any application:
// Example: Login request
const response = await fetch('http://localhost:5000/User/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
password: 'password123'
})
});
const data = await response.json();
const token = data.token;
// Use token in subsequent requests
const userResponse = await fetch('http://localhost:5000/User/1', {
headers: { 'Authorization': `Bearer ${token}` }
});Reuse NAuth React components:
import { UserProvider, useUser } from 'nauth-core';
function App() {
return (
<UserProvider apiUrl="http://localhost:5000">
<YourApp />
</UserProvider>
);
}
function LoginPage() {
const { loginWithEmail, user, loading } = useUser();
const handleLogin = async (email, password) => {
const result = await loginWithEmail(email, password);
if (result.sucesso) {
// Login successful
}
};
return (
// Your login form
);
}Import NAuth services directly (coming soon via NuGet):
// Add NAuth to your project
services.AddNAuth(Configuration);
// Use in your controllers
public class MyController : Controller
{
private readonly IUserService _userService;
public MyController(IUserService userService)
{
_userService = userService;
}
}Using Docker Compose:
docker-compose up -d --buildOr manually without Docker:
dotnet run --project NAuth.API# Use staging configuration
docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d --build# Use production configuration
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build-
Build and push image:
docker build -t your-registry.azurecr.io/nauth-api:latest . docker push your-registry.azurecr.io/nauth-api:latest -
Deploy to Azure:
az container create --resource-group myResourceGroup \ --name nauth-api \ --image your-registry.azurecr.io/nauth-api:latest \ --dns-name-label nauth-api \ --ports 80 443
- Create task definition with NAuth and PostgreSQL containers
- Create ECS service
- Configure Application Load Balancer
- Set up RDS for PostgreSQL
# Example deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nauth-api
spec:
replicas: 3
selector:
matchLabels:
app: nauth-api
template:
metadata:
labels:
app: nauth-api
spec:
containers:
- name: nauth-api
image: your-registry/nauth-api:latest
ports:
- containerPort: 80
env:
- name: ConnectionStrings__NAuthContext
valueFrom:
secretKeyRef:
name: nauth-secrets
key: connection-stringThe project includes a GitHub Actions workflow for automated Docker builds.
Workflow triggers:
- Push to
mainordevelopbranches - Pull requests to
main - Tags matching
v*pattern
Workflow steps:
- Build Docker images for API and PostgreSQL
- Push images to GitHub Container Registry (ghcr.io)
- Create image tags based on:
- Branch name
- Semver version
- Commit SHA
Using the images:
docker pull ghcr.io/landim32/nauth/nauth-api:main
docker pull ghcr.io/landim32/nauth/nauth-postgres:main- Two-Factor Authentication (2FA) - TOTP and SMS support
- OAuth2 Integration - Social login providers
- GitHub
- Microsoft
- Admin Dashboard - Web interface for user management
- Advanced RBAC - Fine-grained permissions
- Audit Logging - Track user actions
- Rate Limiting - API request throttling
- Session Management - Multiple device support
- Account Lockout - Brute force protection
- Password Policies - Configurable complexity rules
- User Invitations - Admin-initiated registration
- NuGet Package - Easy integration via NuGet
- Localization - Multi-language support
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Make your changes
- Run tests (
dotnet test) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Follow C# coding conventions
- Write unit tests for new features
- Update documentation as needed
- Keep commits atomic and well-described
Developed by Rodrigo Landim Carneiro
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with .NET 8
- Database powered by PostgreSQL
- Frontend with React
- Containerization with Docker
- Documentation inspired by best practices in open source
- Issues: GitHub Issues
- Discussions: GitHub Discussions
β If you find this project useful, please consider giving it a star!