Authentication API Reference
Complete API reference for RamAPI's JWT authentication and password hashing utilities.
Table of Contents
JWTService
Service class for signing and verifying JWT tokens.
Constructor
class JWTService {
constructor(config: JWTConfig)
}JWTConfig
interface JWTConfig {
secret: string;
expiresIn?: number;
algorithm?: jwt.Algorithm;
issuer?: string;
audience?: string;
}Options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
secret | string | Yes | - | Secret key for signing tokens |
expiresIn | number | No | undefined | Expiration time in seconds |
algorithm | jwt.Algorithm | No | 'HS256' | JWT signing algorithm |
issuer | string | No | undefined | Token issuer |
audience | string | No | undefined | Token audience |
Methods
sign()
Sign a JWT token.
sign(payload: JWTPayload): stringParameters:
| Parameter | Type | Description |
|---|---|---|
payload | JWTPayload | Token payload |
Returns: string - Signed JWT token
Example:
const jwtService = new JWTService({
secret: process.env.JWT_SECRET!,
expiresIn: 86400, // 24 hours
});
const token = jwtService.sign({
sub: '123', // User ID
email: 'user@example.com',
role: 'admin',
});
console.log(token);
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...verify()
Verify and decode a JWT token.
verify(token: string): JWTPayloadParameters:
| Parameter | Type | Description |
|---|---|---|
token | string | JWT token to verify |
Returns: JWTPayload - Decoded token payload
Throws:
HTTPError(401)if token is expiredHTTPError(401)if token is invalid
Example:
try {
const payload = jwtService.verify(token);
console.log(payload);
// { sub: '123', email: 'user@example.com', role: 'admin', iat: ..., exp: ... }
} catch (error) {
console.error('Token verification failed:', error.message);
}decode()
Decode token without verification (use with caution).
decode(token: string): JWTPayload | nullParameters:
| Parameter | Type | Description |
|---|---|---|
token | string | JWT token to decode |
Returns: JWTPayload | null - Decoded payload or null
Example:
const payload = jwtService.decode(token);
console.log(payload?.sub); // User ID (not verified!)JWTPayload
JWT payload structure.
interface JWTPayload {
sub: string; // Subject (user ID)
[key: string]: unknown;
}Common fields:
sub: Subject (user ID) - requirediat: Issued at (timestamp)exp: Expiration (timestamp)iss: Issueraud: Audience- Custom fields: Add any additional data
Example:
const payload: JWTPayload = {
sub: '123',
email: 'user@example.com',
role: 'admin',
permissions: ['read', 'write'],
};authenticate()
Middleware factory for JWT authentication.
Signature
function authenticate(jwtService: JWTService): MiddlewareParameters
| Parameter | Type | Description |
|---|---|---|
jwtService | JWTService | JWT service instance |
Returns
Middleware - Authentication middleware
Behavior
- Extracts token from
Authorizationheader - Verifies token using JWT service
- Sets
ctx.userwith decoded payload - Throws
HTTPError(401)if token is missing or invalid
Example
import { JWTService, authenticate } from 'ramapi';
const jwtService = new JWTService({
secret: process.env.JWT_SECRET!,
expiresIn: 86400,
});
const auth = authenticate(jwtService);
// Protected route
app.get('/profile', auth, async (ctx) => {
console.log(ctx.user);
// { sub: '123', email: 'user@example.com', ... }
ctx.json({ profile: ctx.user });
});optionalAuthenticate()
Middleware factory for optional JWT authentication.
Signature
function optionalAuthenticate(jwtService: JWTService): MiddlewareParameters
| Parameter | Type | Description |
|---|---|---|
jwtService | JWTService | JWT service instance |
Returns
Middleware - Optional authentication middleware
Behavior
- Checks for
Authorizationheader - If present, verifies token and sets
ctx.user - If missing or invalid, continues without setting
ctx.user - Never throws authentication errors
Example
import { JWTService, optionalAuthenticate } from 'ramapi';
const jwtService = new JWTService({
secret: process.env.JWT_SECRET!,
});
const optionalAuth = optionalAuthenticate(jwtService);
// Public route with optional auth
app.get('/posts', optionalAuth, async (ctx) => {
if (ctx.user) {
// Authenticated user - show private posts
const posts = await getPostsForUser(ctx.user.sub);
ctx.json({ posts });
} else {
// Anonymous user - show public posts only
const posts = await getPublicPosts();
ctx.json({ posts });
}
});PasswordService
Service for hashing and verifying passwords using bcrypt.
hash()
Hash a password.
async hash(password: string): Promise\<string\>Parameters:
| Parameter | Type | Description |
|---|---|---|
password | string | Plain text password |
Returns: Promise\<string\> - Hashed password
Example:
import { passwordService } from 'ramapi';
const hashedPassword = await passwordService.hash('myPassword123');
console.log(hashedPassword);
// $2b$10$...verify()
Verify a password against a hash.
async verify(password: string, hash: string): Promise\<boolean\>Parameters:
| Parameter | Type | Description |
|---|---|---|
password | string | Plain text password |
hash | string | Hashed password |
Returns: Promise\<boolean\> - True if password matches
Example:
const isValid = await passwordService.verify('myPassword123', hashedPassword);
if (isValid) {
console.log('Password correct');
} else {
console.log('Password incorrect');
}passwordService
Pre-configured global instance of PasswordService.
import { passwordService } from 'ramapi';
// Hash password
const hash = await passwordService.hash(password);
// Verify password
const valid = await passwordService.verify(password, hash);Complete Examples
User Registration
import { createApp, validate, passwordService, JWTService } from 'ramapi';
import { z } from 'zod';
const app = createApp();
const jwtService = new JWTService({
secret: process.env.JWT_SECRET!,
expiresIn: 86400, // 24 hours
});
app.post('/auth/register',
validate({
body: z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string().min(2),
}),
}),
async (ctx) => {
const { email, password, name } = ctx.body;
// Check if user exists
const existing = await db.getUserByEmail(email);
if (existing) {
ctx.json({ error: 'Email already registered' }, 409);
return;
}
// Hash password
const hashedPassword = await passwordService.hash(password);
// Create user
const user = await db.createUser({
email,
password: hashedPassword,
name,
});
// Generate token
const token = jwtService.sign({
sub: user.id,
email: user.email,
role: user.role,
});
ctx.json({
user: {
id: user.id,
email: user.email,
name: user.name,
},
token,
}, 201);
}
);User Login
import { authenticate } from 'ramapi';
app.post('/auth/login',
validate({
body: z.object({
email: z.string().email(),
password: z.string(),
}),
}),
async (ctx) => {
const { email, password } = ctx.body;
// Get user
const user = await db.getUserByEmail(email);
if (!user) {
ctx.json({ error: 'Invalid credentials' }, 401);
return;
}
// Verify password
const valid = await passwordService.verify(password, user.password);
if (!valid) {
ctx.json({ error: 'Invalid credentials' }, 401);
return;
}
// Generate token
const token = jwtService.sign({
sub: user.id,
email: user.email,
role: user.role,
});
ctx.json({
user: {
id: user.id,
email: user.email,
name: user.name,
},
token,
});
}
);Protected Routes
const auth = authenticate(jwtService);
// Get current user profile
app.get('/profile', auth, async (ctx) => {
const userId = ctx.user.sub;
const user = await db.getUserById(userId);
ctx.json({ user });
});
// Update profile
app.put('/profile',
auth,
validate({
body: z.object({
name: z.string().min(2).optional(),
bio: z.string().max(500).optional(),
}),
}),
async (ctx) => {
const userId = ctx.user.sub;
const updates = ctx.body;
const user = await db.updateUser(userId, updates);
ctx.json({ user });
}
);Role-Based Access Control
// Middleware factory for role checking
function requireRole(role: string): Middleware {
return async (ctx, next) => {
if (!ctx.user) {
ctx.json({ error: 'Unauthorized' }, 401);
return;
}
if (ctx.user.role !== role) {
ctx.json({ error: 'Forbidden' }, 403);
return;
}
await next();
};
}
const auth = authenticate(jwtService);
const adminOnly = requireRole('admin');
// Admin-only route
app.delete('/users/:id',
auth,
adminOnly,
async (ctx) => {
await db.deleteUser(ctx.params.id);
ctx.status(204);
}
);Token Refresh
app.post('/auth/refresh',
auth,
async (ctx) => {
// Generate new token
const newToken = jwtService.sign({
sub: ctx.user.sub,
email: ctx.user.email,
role: ctx.user.role,
});
ctx.json({ token: newToken });
}
);Custom JWT Claims
const jwtService = new JWTService({
secret: process.env.JWT_SECRET!,
expiresIn: 86400,
issuer: 'my-app',
audience: 'api.example.com',
});
// Sign with custom claims
const token = jwtService.sign({
sub: user.id,
email: user.email,
role: user.role,
permissions: ['read', 'write'],
sessionId: generateSessionId(),
});
// Verify includes issuer/audience checks
const payload = jwtService.verify(token);Security Best Practices
1. Use Strong Secrets
// Bad
const jwtService = new JWTService({ secret: 'secret' });
// Good
const jwtService = new JWTService({
secret: process.env.JWT_SECRET!, // Long, random string
});2. Set Expiration
const jwtService = new JWTService({
secret: process.env.JWT_SECRET!,
expiresIn: 86400, // 24 hours
});3. Use HTTPS
Always use HTTPS in production to protect tokens in transit.
4. Store Tokens Securely
- Don't store in localStorage (XSS vulnerable)
- Use httpOnly cookies or secure storage
- Clear tokens on logout
5. Validate All Inputs
app.post('/auth/login',
validate({
body: z.object({
email: z.string().email(),
password: z.string().min(1), // Don't reveal length requirements to attackers
}),
}),
async (ctx) => {
// ...
}
);See Also
- Authentication Guide - JWT authentication guide
- Password Hashing Guide - Password security guide
- Middleware API - Built-in middleware
Need help? Check the Authentication Guide or GitHub Issues (opens in a new tab).