# 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

```bash
cp .env.example .env
# Edit DATABASE_URL in .env
```

### 3. Run with Docker Compose

```bash
docker-compose up -d
```

Service available at: `http://localhost:5001`

### 4. Run Locally

```bash
dotnet restore
dotnet build
dotnet run --project src/IamService.API
```

## Database Migrations

### Prerequisites

```bash
# Install EF Core tools (one-time)
dotnet tool install --global dotnet-ef
```

### Create Migration

```bash
dotnet ef migrations add <MigrationName> \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API
```

### Apply Migration

```bash
dotnet ef database update \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API
```

### Neon Database Setup

1. Create database on [Neon Console](https://console.neon.tech)
2. Copy connection string
3. Update `appsettings.Development.json`:
```json
{
  "ConnectionStrings": {
    "DefaultConnection": "Host=<host>;Port=5432;Database=<db>;Username=<user>;Password=<pass>;SSL Mode=Require"
  }
}
```
4. 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

```bash
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:**
```json
{
  "success": true,
  "data": {
    "userId": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com"
  }
}
```

### Step 2: Login (Password Grant)

```bash
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:**
```json
{
  "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:

```bash
curl http://localhost:5001/api/v1/users/me \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9..."
```

### Step 4: Refresh Token (When Access Token Expires)

```bash
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

```bash
curl -X POST http://localhost:5001/api/v1/auth/logout \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

### Client Credentials (Service-to-Service)

```bash
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

```bash
# Restore dependencies
dotnet restore

# Build
dotnet build

# Run tests
dotnet test

# Run API
dotnet run --project src/IamService.API
```

## Docker

```bash
# Build image
docker build -t iam-service:latest .

# Run container
docker run -p 5001:8080 --env-file .env iam-service:latest
```

## Resources

- [OpenIddict Documentation](https://documentation.openiddict.com/)
- [ASP.NET Core Identity](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity)
- [eShopOnContainers](https://github.com/dotnet-architecture/eShopOnContainers)

## License

Proprietary - GoodGo Platform
