@siran/auth-http
v0.1.8
Published
Framework-agnostic HTTP core for Siran Auth - types, handlers, and port interfaces
Downloads
313
Readme
@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:
HttpRequestandHttpResponseinterfaces 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
AuthHandlersclass - Error Mapping:
AuthErrorCode→ HTTP status codes with user-friendly messages - Request Parsing: Utilities to convert request bodies to
AuthMethodtypes
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
npm install @siran/auth-http @siran/auth-coreUsage
Basic Setup
import { AuthHandlers } from '@siran/auth-http';
import { createAuthEngine } from '@siran/auth-core';
const authEngine = createAuthEngine({
// Configuration...
});
const handlers = new AuthHandlers({ authEngine });With Token Provider
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
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)
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.
class AuthHandlers {
constructor(options: HandlerOptions);
login(body: LoginRequestBody): Promise<HandlerResult>;
register(body: RegisterRequestBody): Promise<HandlerResult>;
logout(sessionId?: string, userId?: string): Promise<HandlerResult>;
}Request Bodies
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
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:
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:
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
import { parseLoginRequest, parseRegisterRequest } from '@siran/auth-http';
const authMethod = parseLoginRequest(req.body);
// Throws ParseError if invalidError Handling
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:
nx test @siran/auth-httpRun tests with coverage:
nx test @siran/auth-http --coverageThe 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:
- Import
AuthHandlersand types from@siran/auth-http - Implement
HttpRequestandHttpResponseinterfaces - Create middleware/routes that call the handler methods
- Map framework-specific request/response to the HTTP abstractions
Example structure:
// 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:
nx build @siran/auth-httpType checking:
nx typecheck @siran/auth-httpLicense
Part of the Siran Auth project.
