# Authentication System

Effect-TS based authentication system for MyAIDev Method web server.

## Architecture

### Services Layer

**AuthService** - High-level authentication orchestration
- `register()` - User registration with validation
- `login()` - User authentication with session creation
- `logout()` - Session revocation
- `verifyToken()` - JWT verification and session validation

**PasswordService** - Password hashing and validation
- `hash()` - bcrypt password hashing (12 rounds)
- `verify()` - Password verification
- `validatePasswordStrength()` - Password strength requirements

**TokenService** - JWT token management
- `generateToken()` - Create signed JWT (RS256)
- `verifyToken()` - Verify and decode JWT
- `hashToken()` - SHA-256 token hashing

**UserRepository** - User data persistence
- `create()` - Create new user
- `findById()` - Find user by ID
- `findByEmail()` - Find user by email
- `findByUsername()` - Find user by username
- `update()` - Update user data
- `incrementFailedLogins()` - Track failed login attempts
- `resetFailedLogins()` - Reset failed login counter

**SessionRepository** - Session management
- `create()` - Create new session
- `findById()` - Find session by ID
- `findByTokenHash()` - Find session by token hash
- `revoke()` - Revoke single session
- `revokeAllForUser()` - Revoke all user sessions
- `deleteExpired()` - Clean up expired sessions

**AuditLogService** - Security audit logging
- `log()` - Record security events

### Middleware

**authMiddleware** - Hono middleware for route protection
- Extracts token from `Authorization: Bearer <token>` or `auth_token` cookie
- Verifies token and session validity
- Injects `user` and `session` into Hono context
- Returns 401 for authentication failures

### Routes

**POST /api/auth/register**
```typescript
Request: { username: string; email: string; password: string }
Response: { user: { id, username, email, emailVerified } }
Status: 201 Created | 400 Validation Error | 500 Server Error
```

**POST /api/auth/login**
```typescript
Request: { email: string; password: string }
Response: { user: { id, username, email, emailVerified }, token: string }
Cookie: auth_token (httpOnly, secure, sameSite=strict)
Status: 200 OK | 401 Unauthorized | 500 Server Error
```

**POST /api/auth/logout** (requires auth)
```typescript
Response: { message: "Logged out successfully" }
Status: 200 OK | 401 Unauthorized | 500 Server Error
```

**GET /api/auth/me** (requires auth)
```typescript
Response: { user: { id, username, email, emailVerified, createdAt, lastLoginAt } }
Status: 200 OK | 401 Unauthorized | 500 Server Error
```

## Security Features

### Password Requirements
- Minimum 8 characters
- At least 1 uppercase letter
- At least 1 lowercase letter
- At least 1 number
- Hashed with bcrypt (12 rounds)

### Account Lockout
- 5 failed login attempts triggers lockout
- 15 minute lockout duration
- Automatic unlock after duration expires
- Failed attempts reset on successful login

### Session Management
- JWT tokens with RS256 signing
- 7 day token expiration
- Session stored with token hash (SHA-256)
- Session validation on every request
- Revocable sessions

### Cookie Configuration
```typescript
{
  httpOnly: true,
  secure: process.env.NODE_ENV === "production",
  sameSite: "strict",
  maxAge: 7 * 24 * 60 * 60, // 7 days
  path: "/"
}
```

### Linux Username Generation
- Sanitized from user's username
- Lowercase alphanumeric + underscores
- Must start with letter
- Max 32 characters
- Guaranteed unique with counter suffix if needed

## Usage Example

### Integration with Hono

```typescript
import { Hono } from "hono";
import { authRouter, authMiddleware } from "./auth/index.js";

const app = new Hono();

// Public routes
app.route("/api/auth", authRouter);

// Protected routes
app.get("/api/protected", authMiddleware, (c) => {
  const user = c.get("user");
  const session = c.get("session");
  return c.json({ message: `Hello ${user.username}` });
});

export default app;
```

### Direct Service Usage

```typescript
import { Effect } from "effect";
import { AppLayer } from "./auth/middleware/authMiddleware.js";
import { AuthService } from "./auth/services/AuthService.js";

const registerUser = Effect.gen(function* () {
  const authService = yield* AuthService;
  const user = yield* authService.register(
    "testuser",
    "test@example.com",
    "SecurePass123",
    "127.0.0.1",
    "Mozilla/5.0"
  );
  return user;
});

const user = await Effect.runPromise(
  Effect.provide(registerUser, AppLayer)
);
```

## Error Handling

All services use typed Effect errors:

- **AuthError** - Authentication failures (401)
  - `INVALID_CREDENTIALS` - Wrong email/password
  - `ACCOUNT_LOCKED` - Too many failed attempts
  - `TOKEN_EXPIRED` - Session expired
  - `SESSION_REVOKED` - Session invalidated
  - `USER_INACTIVE` - Account disabled

- **ValidationError** - Input validation failures (400)
  - Field-specific error messages
  - Password strength requirements
  - Email format validation

- **DatabaseError** - Database operation failures (500)
  - Generic database errors
  - Connection issues

## Audit Logging

All authentication events are logged:
- `USER_REGISTERED` - New user registration
- `USER_LOGIN` - Successful login
- `USER_LOGOUT` - User logout
- `LOGIN_FAILED` - Failed login attempt
- `ACCOUNT_LOCKED` - Account locked notification

Audit logs include:
- User ID
- Action type
- Resource type and ID
- IP address
- User agent
- Timestamp
- Additional details

## Testing

```typescript
import { describe, it, expect } from "vitest";
import { Effect } from "effect";
import { AppLayer } from "./middleware/authMiddleware.js";
import { AuthService } from "./services/AuthService.js";

describe("AuthService", () => {
  it("should register a new user", async () => {
    const registerEffect = Effect.gen(function* () {
      const authService = yield* AuthService;
      return yield* authService.register(
        "testuser",
        "test@example.com",
        "SecurePass123"
      );
    });

    const user = await Effect.runPromise(
      Effect.provide(registerEffect, AppLayer)
    );

    expect(user.username).toBe("testuser");
    expect(user.email).toBe("test@example.com");
    expect(user.passwordHash).toBeTruthy();
  });
});
```

## Dependencies

- `effect` - Effect-TS for composable error handling
- `hono` - Web framework
- `bcrypt` - Password hashing
- `jose` - JWT handling (RS256)
- `node:crypto` - Token hashing and UUID generation

## Design Patterns

### Effect-TS Context.Tag Pattern
All services use `Context.Tag` for dependency injection:
```typescript
export class ServiceName extends Context.Tag("ServiceName")<
  ServiceName,
  ServiceInterface
>() {
  static Live = Layer.effect(this, Effect.gen(function* () {
    // Dependencies
    const dep = yield* DependencyService;

    // Implementation
    return { method: () => Effect.succeed(result) };
  }));
}
```

### Layer Composition
Dependencies are composed into a single `AppLayer`:
```typescript
export const AppLayer = Layer.mergeAll(
  DatabaseService.Live,
  PasswordService.Live,
  TokenService.Live
).pipe(
  Layer.provideMerge(UserRepository.Live),
  Layer.provideMerge(SessionRepository.Live),
  Layer.provideMerge(AuditLogService.Live),
  Layer.provideMerge(AuthService.Live)
);
```

### Effect.gen for Composition
All business logic uses `Effect.gen` with `yield*`:
```typescript
const operation = Effect.gen(function* () {
  const service = yield* Service;
  const result = yield* service.method();
  return result;
});
```

### No Type Casting
All type conversions are explicit and safe - no `as` type assertions.
