# Authentication Services

This directory contains Effect-TS based authentication services following the ccviewer codebase patterns.

## Architecture

All services follow these principles:

- **Effect-TS Only**: No async/await, no classes except Context.Tag
- **No Type Casting**: No `as` type casting allowed
- **Functional Composition**: Use Effect.gen with yield* for composition
- **Proper Error Handling**: Typed errors (AuthError, ValidationError, DatabaseError)
- **Layer-based DI**: Context.Tag with Layer.effect or Layer.succeed

## Services

### 1. PasswordService

Handles password hashing and validation.

```typescript
import { PasswordService } from "./services/PasswordService.js";

const program = Effect.gen(function* (_) {
  const passwordService = yield* _(PasswordService);

  // Validate password strength
  yield* _(passwordService.validatePasswordStrength("SecurePass123"));

  // Hash password
  const hash = yield* _(passwordService.hash("SecurePass123"));

  // Verify password
  const isValid = yield* _(passwordService.verify("SecurePass123", hash));
});
```

**Methods:**
- `hash(password: string)` - Hash password with bcrypt (cost 12)
- `verify(password: string, hash: string)` - Verify password against hash
- `validatePasswordStrength(password: string)` - Validate password requirements

**Password Requirements:**
- Minimum 8 characters
- At least 1 uppercase letter
- At least 1 lowercase letter
- At least 1 number

### 2. TokenService

JWT token generation and verification using RS256 algorithm.

```typescript
import { TokenService } from "./services/TokenService.js";

const program = Effect.gen(function* (_) {
  const tokenService = yield* _(TokenService);

  // Generate JWT token
  const token = yield* _(tokenService.generateToken({
    sub: "user-id",
    username: "johndoe",
    email: "john@example.com",
    jti: "session-id"
  }));

  // Verify token
  const payload = yield* _(tokenService.verifyToken(token));

  // Hash token for database storage
  const tokenHash = yield* _(tokenService.hashToken(token));
});
```

**Methods:**
- `generateToken(payload)` - Generate JWT with RS256 (7 day expiry)
- `verifyToken(token)` - Verify token signature and expiration
- `hashToken(token)` - SHA-256 hash for database storage

**Key Generation:**
- RS256 key pair generated at service initialization
- Keys stored in memory (can be modified to use environment variables)

### 3. UserRepository

User CRUD operations with database integration.

```typescript
import { UserRepository } from "./services/UserRepository.js";

const program = Effect.gen(function* (_) {
  const userRepo = yield* _(UserRepository);

  // Create user
  const user = yield* _(userRepo.create({
    username: "johndoe",
    email: "john@example.com",
    passwordHash: "hashed-password",
    linuxUsername: "john-doe"
  }));

  // Find by email
  const found = yield* _(userRepo.findByEmail("john@example.com"));

  // Update user
  const updated = yield* _(userRepo.update(user.id, {
    emailVerified: true
  }));

  // Manage failed logins
  yield* _(userRepo.incrementFailedLogins(user.id));
  yield* _(userRepo.resetFailedLogins(user.id));
});
```

**Methods:**
- `create(data)` - Create new user with generated UUID
- `findById(id)` - Find user by ID
- `findByEmail(email)` - Find user by email
- `findByUsername(username)` - Find user by username
- `update(id, data)` - Update user fields
- `incrementFailedLogins(id)` - Increment failed login counter
- `resetFailedLogins(id)` - Reset failed login counter

### 4. SessionRepository

Session management with token hash storage.

```typescript
import { SessionRepository } from "./services/SessionRepository.js";

const program = Effect.gen(function* (_) {
  const sessionRepo = yield* _(SessionRepository);

  // Create session
  const session = yield* _(sessionRepo.create({
    userId: "user-id",
    tokenHash: "sha256-hash",
    ipAddress: "127.0.0.1",
    userAgent: "Mozilla/5.0",
    expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000
  }));

  // Find by token hash
  const found = yield* _(sessionRepo.findByTokenHash("sha256-hash"));

  // Revoke session
  yield* _(sessionRepo.revoke(session.id));

  // Revoke all user sessions
  yield* _(sessionRepo.revokeAllForUser("user-id"));

  // Clean up expired sessions
  const deletedCount = yield* _(sessionRepo.deleteExpired());
});
```

**Methods:**
- `create(data)` - Create new session with generated UUID
- `findById(id)` - Find session by ID
- `findByTokenHash(tokenHash)` - Find session by token hash
- `revoke(id)` - Revoke single session
- `revokeAllForUser(userId)` - Revoke all user sessions
- `deleteExpired()` - Delete expired sessions (returns count)

### 5. AuditLogService

Audit logging for security and compliance.

```typescript
import { AuditLogService } from "./services/AuditLogService.js";

const program = Effect.gen(function* (_) {
  const auditLog = yield* _(AuditLogService);

  // Log user action
  yield* _(auditLog.log({
    userId: "user-id",
    action: "USER_LOGIN",
    resourceType: "session",
    resourceId: "session-id",
    ipAddress: "127.0.0.1",
    userAgent: "Mozilla/5.0",
    details: JSON.stringify({ method: "password" })
  }));
});
```

**Methods:**
- `log(data)` - Create audit log entry

**Predefined Actions:**
- `USER_REGISTERED` - New user registration
- `USER_LOGIN` - Successful login
- `USER_LOGOUT` - User logout
- `LOGIN_FAILED` - Failed login attempt
- `PASSWORD_CHANGED` - Password update
- `PASSWORD_RESET_REQUESTED` - Password reset initiated
- `PASSWORD_RESET_COMPLETED` - Password reset completed
- `EMAIL_VERIFIED` - Email verification
- `EMAIL_CHANGED` - Email address update
- `PROFILE_UPDATED` - Profile information update
- `ACCOUNT_LOCKED` - Account locked
- `ACCOUNT_UNLOCKED` - Account unlocked
- `SESSION_CREATED` - New session created
- `SESSION_REVOKED` - Session revoked
- `TOKEN_REFRESHED` - Token refreshed
- `OAUTH_LINKED` - OAuth provider linked
- `OAUTH_UNLINKED` - OAuth provider unlinked
- `TWO_FACTOR_ENABLED` - 2FA enabled
- `TWO_FACTOR_DISABLED` - 2FA disabled

## Layer Composition

Create a complete authentication layer:

```typescript
import { Layer } from "effect";
import { DatabaseService } from "../../database/db.js";
import {
  PasswordService,
  TokenService,
  UserRepository,
  SessionRepository,
  AuditLogService
} from "./services/index.js";

// Combine authentication services
const AuthenticationLayer = Layer.mergeAll(
  PasswordService.Live,
  TokenService.Live,
  UserRepository.Live,
  SessionRepository.Live,
  AuditLogService.Live
);

// Complete application layer with database
const AppLayer = Layer.mergeAll(
  DatabaseService.Live({ path: "./app.db" }),
  AuthenticationLayer
);

// Use in your program
const program = Effect.gen(function* (_) {
  // Your authentication logic here
});

Effect.runPromise(program.pipe(Effect.provide(AppLayer)));
```

## Complete Examples

See `example.ts` for complete authentication flows:

1. **User Registration Flow**
   - Password validation
   - Password hashing
   - User creation
   - Audit logging

2. **Login Flow**
   - User lookup
   - Password verification
   - Token generation
   - Session creation
   - Failed login tracking
   - Audit logging

3. **Token Verification Flow**
   - JWT verification
   - Session validation
   - User status check

4. **Logout Flow**
   - Session revocation
   - Audit logging

## Database Schema

All services require these database tables (already defined in `src/server/database/schema.sql`):

- `users` - User accounts
- `sessions` - Active sessions with token hashes
- `audit_logs` - Security audit trail

## Error Handling

All services use typed errors from `src/shared/types.ts`:

- **AuthError** - Authentication/authorization failures
- **ValidationError** - Input validation failures
- **DatabaseError** - Database operation failures

```typescript
import { AuthError, ValidationError, DatabaseError } from "../../../shared/types.js";

const program = Effect.gen(function* (_) {
  // Handle specific error types
}).pipe(
  Effect.catchTag("AuthError", (error) =>
    Effect.succeed({ error: error.message })
  ),
  Effect.catchTag("ValidationError", (error) =>
    Effect.succeed({ field: error.field, error: error.message })
  )
);
```

## Testing

All services can be tested using Effect test layers:

```typescript
import { expect, test } from "vitest";
import { Effect, Layer } from "effect";
import { DatabaseService } from "../../database/db.js";
import { PasswordService } from "./PasswordService.js";

test("password hashing and verification", async () => {
  const program = Effect.gen(function* (_) {
    const passwordService = yield* _(PasswordService);
    const hash = yield* _(passwordService.hash("SecurePass123"));
    const isValid = yield* _(passwordService.verify("SecurePass123", hash));
    return isValid;
  });

  const testLayer = Layer.mergeAll(
    DatabaseService.Live({ path: ":memory:" }),
    PasswordService.Live
  );

  const result = await Effect.runPromise(
    program.pipe(Effect.provide(testLayer))
  );

  expect(result).toBe(true);
});
```

## Security Considerations

1. **Password Storage**: Bcrypt with cost factor 12
2. **Token Storage**: Never store raw JWT tokens, use SHA-256 hash
3. **Session Management**: Track and revoke sessions
4. **Audit Trail**: Log all security-relevant actions
5. **Failed Login Tracking**: Monitor and limit failed attempts
6. **Token Expiry**: 7-day expiration (configurable)

## Dependencies

- `effect` - Effect-TS runtime
- `bcrypt` - Password hashing
- `jose` - JWT operations
- `better-sqlite3` - Database (via DatabaseService)
- `node:crypto` - UUID generation and SHA-256 hashing

## References

- Effect-TS documentation: https://effect.website/
- ccviewer patterns: `/home/ubuntu/projects/myaidev-method/ccviewer/`
- Database schema: `/home/ubuntu/projects/myaidev-method/src/server/database/schema.sql`
