Add authentication system with session-based auth
Implements full auth flows with opaque tokens (not JWT) for easy revocation: - Login/logout with cookie or bearer token support - Registration with email verification - Password reset with one-time tokens - scrypt password hashing (no external deps) New files in express/auth/: - token.ts: 256-bit token generation, SHA-256 hashing - password.ts: scrypt hashing with timing-safe verification - types.ts: Session schemas, token types, input validation - store.ts: AuthStore interface + InMemoryAuthStore - service.ts: AuthService with all auth operations - routes.ts: 6 auth endpoints Modified: - types.ts: Added user field to Call, requireAuth/requirePermission helpers - app.ts: JSON body parsing, populates call.user, handles auth errors - services.ts: Added services.auth - routes.ts: Includes auth routes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
40
express/auth/token.ts
Normal file
40
express/auth/token.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
// token.ts
|
||||
//
|
||||
// Token generation and hashing utilities for authentication.
|
||||
// Raw tokens are never stored - only their SHA-256 hashes.
|
||||
|
||||
import { createHash, randomBytes } from "node:crypto";
|
||||
|
||||
const TOKEN_BYTES = 32; // 256 bits of entropy
|
||||
|
||||
// Generate a cryptographically secure random token
|
||||
function generateToken(): string {
|
||||
return randomBytes(TOKEN_BYTES).toString("base64url");
|
||||
}
|
||||
|
||||
// Hash token for storage (never store raw tokens)
|
||||
function hashToken(token: string): string {
|
||||
return createHash("sha256").update(token).digest("hex");
|
||||
}
|
||||
|
||||
// Parse token from Authorization header
|
||||
function parseAuthorizationHeader(header: string | undefined): string | null {
|
||||
if (!header) return null;
|
||||
|
||||
const parts = header.split(" ");
|
||||
if (parts.length !== 2 || parts[0].toLowerCase() !== "bearer") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parts[1];
|
||||
}
|
||||
|
||||
// Cookie name for web sessions
|
||||
const SESSION_COOKIE_NAME = "diachron_session";
|
||||
|
||||
export {
|
||||
generateToken,
|
||||
hashToken,
|
||||
parseAuthorizationHeader,
|
||||
SESSION_COOKIE_NAME,
|
||||
};
|
||||
Reference in New Issue
Block a user