…
IAM Service .NET
Identity and Access Management Service built with .NET 10, ASP.NET Core Identity, and OpenIddict.
Overview
IAM Service provides OAuth2/OpenID Connect authentication and authorization capabilities:
- User Management: Registration, profile management, account locking
- Role-Based Access Control (RBAC): Role assignment, permission management
- OAuth2 Token Endpoints: Password, Refresh Token, Client Credentials grants
- JWT Tokens: Access tokens (15 min), Refresh tokens (7 days)
Tech Stack
| Technology | Purpose |
|---|---|
| .NET 10 | Runtime |
| ASP.NET Core Identity | User/Role management |
| OpenIddict | OAuth2/OIDC server |
| EF Core + PostgreSQL | Data persistence |
| MediatR | CQRS pattern |
| FluentValidation | Request validation |
| Serilog | Structured logging |
Quick Start
1. Prerequisites
- .NET SDK 10.0.101+
- Docker (for PostgreSQL)
2. Setup Environment
cp .env.example .env
# Edit DATABASE_URL in .env
3. Run with Docker Compose
docker-compose up -d
Service available at: http://localhost:5001
4. Run Locally
dotnet restore
dotnet build
dotnet run --project src/IamService.API
Database Migrations
Prerequisites
# Install EF Core tools (one-time)
dotnet tool install --global dotnet-ef
Create Migration
dotnet ef migrations add <MigrationName> \
--project src/IamService.Infrastructure \
--startup-project src/IamService.API
Apply Migration
dotnet ef database update \
--project src/IamService.Infrastructure \
--startup-project src/IamService.API
Neon Database Setup
- Create database on Neon Console
- Copy connection string
- Update
appsettings.Development.json:
{
"ConnectionStrings": {
"DefaultConnection": "Host=<host>;Port=5432;Database=<db>;Username=<user>;Password=<pass>;SSL Mode=Require"
}
}
- Run migrations:
dotnet ef database update ...
API Endpoints
Authentication (/api/v1/auth)
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST |
/api/v1/auth/register |
Register new user | ❌ |
POST |
/connect/token |
OAuth2 token endpoint (login, refresh) | ❌ |
POST |
/api/v1/auth/change-password |
Change password | ✅ |
POST |
/api/v1/auth/logout |
Logout (revoke tokens) | ✅ |
User Management (/api/v1/users)
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/api/v1/users |
List users (paginated) | ✅ |
GET |
/api/v1/users/me |
Get current user | ✅ |
GET |
/api/v1/users/{id} |
Get user by ID | ✅ |
PUT |
/api/v1/users/{id} |
Update user | ✅ |
DELETE |
/api/v1/users/{id} |
Delete user (soft delete) | ✅ |
Authentication Flow
Step 1: Register a New User
curl -X POST http://localhost:5001/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "Password123!",
"firstName": "John",
"lastName": "Doe"
}'
Response:
{
"success": true,
"data": {
"userId": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com"
}
}
Step 2: Login (Password Grant)
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "username=user@example.com" \
-d "password=Password123!" \
-d "scope=openid profile email offline_access"
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9...",
"scope": "openid profile email offline_access"
}
Step 3: Use Access Token
Use the access_token in Authorization header for protected APIs:
curl http://localhost:5001/api/v1/users/me \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9..."
Step 4: Refresh Token (When Access Token Expires)
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9..."
Step 5: Logout
curl -X POST http://localhost:5001/api/v1/auth/logout \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Client Credentials (Service-to-Service)
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=goodgo-service" \
-d "client_secret=service-secret" \
-d "scope=api"
Health Checks
| Endpoint | Purpose |
|---|---|
/health |
Full health status |
/health/live |
Liveness probe |
/health/ready |
Readiness probe |
Swagger UI
After running the service, access Swagger UI at:
- Local: http://localhost:5001/swagger
- Docker: http://localhost/api/v1/iam/swagger
Project Structure
iam-service-net/
├── src/
│ ├── IamService.API/ # Controllers, CQRS
│ │ ├── Controllers/ # AuthController, UsersController
│ │ └── Application/ # Commands, Queries, Validations
│ ├── IamService.Domain/ # Domain entities
│ │ ├── AggregatesModel/ # UserAggregate, RoleAggregate
│ │ ├── Events/ # Domain events
│ │ └── Exceptions/ # Domain exceptions
│ └── IamService.Infrastructure/ # Data access
│ ├── IamServiceContext.cs # DbContext with Identity
│ └── Repositories/ # Repository implementations
├── tests/
│ ├── IamService.UnitTests/
│ └── IamService.FunctionalTests/
├── Dockerfile
└── docker-compose.yml
Configuration
Environment Variables
| Variable | Description | Default |
|---|---|---|
ASPNETCORE_ENVIRONMENT |
Environment | Development |
DATABASE_URL |
PostgreSQL connection | - |
JWT_SECRET |
JWT signing secret (32+ chars) | - |
REDIS_URL |
Redis connection | - |
Password Policy
- Minimum 8 characters
- Requires uppercase, lowercase, digit, special character
Token Lifetimes
| Token | Lifetime |
|---|---|
| Access Token | 15 minutes |
| Refresh Token | 7 days |
Development
# Restore dependencies
dotnet restore
# Build
dotnet build
# Run tests
dotnet test
# Run API
dotnet run --project src/IamService.API
Docker
# Build image
docker build -t iam-service:latest .
# Run container
docker run -p 5001:8080 --env-file .env iam-service:latest
Resources
License
Proprietary - GoodGo Platform