npm package: @siran/auth-http
Description: Framework-agnostic HTTP core for Siran Auth - types, handlers, and port interfaces
Latest version: 0.1.8

# @siran/auth-http

Framework-agnostic HTTP core for Siran Auth - types, handlers, and port interfaces.

This package provides the foundational HTTP layer for authentication without any framework dependencies. It contains:

- **HTTP Abstractions**: `HttpRequest` and `HttpResponse` interfaces for framework adapters to implement
- **Request/Response DTOs**: Type-safe request bodies and response structures
- **Port Interfaces**: Contracts for optional extensions (token providers, session stores)
- **Core Handler Logic**: Framework-agnostic `AuthHandlers` class
- **Error Mapping**: `AuthErrorCode` → HTTP status codes with user-friendly messages
- **Request Parsing**: Utilities to convert request bodies to `AuthMethod` types

## Architecture

```
@siran/auth-http (this package)
  ├── Core handlers and types
  ├── Port interfaces (contracts)
  └── Error mapping utilities

@siran/auth-http-express (separate package)
  ├── Express middleware/routes
  └── Maps Express Request/Response to HttpRequest/HttpResponse

@siran/auth-http-jwt (separate package)
  ├── Implements TokenProvider port
  └── JWT token generation and verification

@siran/auth-http-sessions (separate package)
  ├── Implements SessionStore port
  ├── Redis session store
  └── In-memory session store (development)
```

## Installation

```bash
npm install @siran/auth-http @siran/auth-core
```

## Usage

### Basic Setup

```typescript
import { AuthHandlers } from '@siran/auth-http';
import { createAuthEngine } from '@siran/auth-core';

const authEngine = createAuthEngine({
  // Configuration...
});

const handlers = new AuthHandlers({ authEngine });
```

### With Token Provider

```typescript
import { AuthHandlers } from '@siran/auth-http';
import { JwtTokenProvider } from '@siran/auth-http-jwt';

const tokenProvider = new JwtTokenProvider({
  secret: process.env.JWT_SECRET,
});

const handlers = new AuthHandlers({
  authEngine,
  tokenProvider,
  sessionExpiresIn: 3600, // 1 hour
});
```

### With Session Store

```typescript
import { AuthHandlers } from '@siran/auth-http';
import { RedisSessionStore } from '@siran/auth-http-sessions';

const sessionStore = new RedisSessionStore({
  redis: redisClient,
});

const handlers = new AuthHandlers({
  authEngine,
  sessionStore,
  sessionExpiresIn: 86400, // 24 hours
});
```

### Framework Adapter Example (Express)

```typescript
import express from 'express';
import { AuthHandlers } from '@siran/auth-http';

const app = express();
app.use(express.json());

const handlers = new AuthHandlers({ authEngine });

app.post('/api/auth/login', async (req, res) => {
  const result = await handlers.login(req.body);
  res.status(result.status).json(result.body);
});

app.post('/api/auth/register', async (req, res) => {
  const result = await handlers.register(req.body);
  res.status(result.status).json(result.body);
});

app.post('/api/auth/logout', async (req, res) => {
  const result = await handlers.logout(req.body.sessionId);
  res.status(result.status).json(result.body);
});
```

## API Documentation

### AuthHandlers

Main handler class that wraps AuthEngine and provides HTTP-compatible methods.

```typescript
class AuthHandlers {
  constructor(options: HandlerOptions);

  login(body: LoginRequestBody): Promise<HandlerResult>;
  register(body: RegisterRequestBody): Promise<HandlerResult>;
  logout(sessionId?: string, userId?: string): Promise<HandlerResult>;
}
```

### Request Bodies

```typescript
type LoginRequestBody =
  | { type: 'password'; identifier: string; password: string }
  | { type: 'otp'; identifier: string; code: string }
  | { type: 'magic_link'; token: string }
  | { type: 'oauth'; provider: 'google' | 'github' | 'apple' | 'facebook'; code: string };

type RegisterRequestBody = LoginRequestBody;
```

### Response Bodies

```typescript
interface AuthSuccessResponse {
  ok: true;
  user: UserAccount;
  token?: string;
  session?: {
    id: string;
    expiresAt: string;
  };
}

interface AuthErrorResponse {
  ok: false;
  error: AuthErrorCode;
  message: string;
  violatedPolicies?: string[];
}

type AuthResponse = AuthSuccessResponse | AuthErrorResponse;
```

### Error Mapping

All `AuthErrorCode` values are mapped to appropriate HTTP status codes:

| Error Code | HTTP Status | Reason |
|---|---|---|
| `INVALID_CREDENTIALS` | 401 | Invalid username/password |
| `ACCOUNT_NOT_VERIFIED` | 403 | Email not verified |
| `ACCOUNT_DISABLED` | 403 | Account disabled |
| `ACCOUNT_LOCKED` | 403 | Account locked due to failed attempts |
| `INVALID_METHOD_PAYLOAD` | 400 | Invalid request format |
| `MISSING_PASSWORD` | 400 | Missing required field |
| `WEAK_PASSWORD` | 422 | Password doesn't meet requirements |
| `ACCOUNT_ALREADY_EXISTS` | 409 | Account already exists |
| `RATE_LIMIT_EXCEEDED` | 429 | Too many attempts |
| `INTERNAL_ERROR` | 500 | Server error |

### Port Interfaces

#### TokenProvider

Implement this to provide custom token generation:

```typescript
interface TokenProvider {
  generate(user: UserAccount, expiresIn?: number): Promise<string>;
  verify(token: string): Promise<TokenPayload | null>;
  decode(token: string): TokenPayload | null;
}
```

#### SessionStore

Implement this to provide custom session storage:

```typescript
interface SessionStore {
  create(userId: string, expiresIn: number): Promise<SessionData>;
  get(sessionId: string): Promise<SessionData | null>;
  delete(sessionId: string): Promise<void>;
  deleteByUser(userId: string): Promise<void>;
  refresh(sessionId: string, expiresIn: number): Promise<SessionData | null>;
}
```

## Utilities

### Request Parsing

```typescript
import { parseLoginRequest, parseRegisterRequest } from '@siran/auth-http';

const authMethod = parseLoginRequest(req.body);
// Throws ParseError if invalid
```

### Error Handling

```typescript
import { mapAuthErrorToHttpStatus, getErrorMessage } from '@siran/auth-http';

const status = mapAuthErrorToHttpStatus('INVALID_CREDENTIALS'); // 401
const message = getErrorMessage('INVALID_CREDENTIALS');
// "Invalid credentials. Please check your identifier and password."
```

## Testing

Run tests:

```bash
nx test @siran/auth-http
```

Run tests with coverage:

```bash
nx test @siran/auth-http --coverage
```

The package includes comprehensive tests for:

- Error mapping (all error codes to HTTP status codes)
- Request parsing (all auth method types)
- Handler logic (login, register, logout with various scenarios)
- Token generation and session creation
- Error handling and edge cases

## Creating Framework Adapters

To create an adapter for a new framework:

1. Import `AuthHandlers` and types from `@siran/auth-http`
2. Implement `HttpRequest` and `HttpResponse` interfaces
3. Create middleware/routes that call the handler methods
4. Map framework-specific request/response to the HTTP abstractions

Example structure:

```typescript
// adapters/express.ts
import type { Request, Response } from 'express';
import type { HttpRequest, HttpResponse } from '@siran/auth-http';

function mapExpressRequest(req: Request): HttpRequest {
  return {
    body: req.body,
    headers: req.headers as Record<string, string>,
    method: req.method,
    url: req.url,
  };
}

function mapExpressResponse(res: Response): HttpResponse {
  return {
    status: (code: number) => {
      res.status(code);
      return mapExpressResponse(res);
    },
    json: (data: unknown) => {
      res.json(data);
    },
    setHeader: (name: string, value: string) => {
      res.setHeader(name, value);
      return mapExpressResponse(res);
    },
  };
}
```

## Dependencies

- `@siran/auth-core`: Core authentication engine and types

## Development

Build the package:

```bash
nx build @siran/auth-http
```

Type checking:

```bash
nx typecheck @siran/auth-http
```

## License

Part of the Siran Auth project.