Sessions & Auth
Cookie-based encrypted sessions and crypto utilities for passwords, JWT, and encryption
Sessions
Cookie-based encrypted sessions using iron-session. This is the recommended authentication approach for Arcway applications. Session data is encrypted and signed in a cookie — no database table, no Bearer tokens, no manual token management.
Configuration
// arcway.config.js
export default {
session: {
// No password — the session signing key is derived from vault.masterSecret.
cookieName: 'my.session', // Default: 'arcway.session'
ttl: 86_400, // 1 day in seconds
secure: true, // Default: true in production, false in dev
},
};Reading Session Data
export const GET = {
handler: async (ctx) => {
if (!ctx.req.session.userId) {
return { status: 401, error: { code: 'UNAUTHORIZED', message: 'Not logged in' } };
}
return { data: { userId: ctx.req.session.userId } };
},
};Setting Session Data (Login)
export const POST = {
handler: async (ctx) => {
const user = await authenticate(ctx.req.body);
return {
data: { user },
session: { userId: user.id, role: user.role }, // Sealed into Set-Cookie
};
},
};Clearing Session (Logout)
export const POST = {
handler: async (ctx) => {
return {
data: { ok: true },
session: null, // Clears the cookie
};
},
};Session Behavior
response.session | Effect |
|---|---|
{ userId: 1 } | Seals data, sets Set-Cookie header |
null | Clears the cookie (Max-Age=0) |
undefined (default) | No change to existing cookie |
Session data is encrypted and signed. Invalid, expired, or tampered cookies return an empty {} session.
Auth Pattern Example
A complete login/logout flow:
// api/auth/login.js
import { vault } from 'arcway';
export const POST = {
handler: async (ctx) => {
const { db } = ctx;
const { email, password } = ctx.req.body;
const user = await db('users').where('email', email).first();
if (!user || !(await vault.verifyPassword(password, user.password_hash))) {
return { status: 401, error: { code: 'INVALID_CREDENTIALS', message: 'Wrong email or password' } };
}
return {
data: { id: user.id, name: user.name },
session: { userId: user.id, role: user.role },
};
},
};
// api/auth/logout.js
export const POST = {
handler: async (ctx) => {
return { data: { ok: true }, session: null };
},
};
// api/auth/me.js
export const GET = {
handler: async (ctx) => {
const { db } = ctx;
if (!ctx.req.session.userId) {
return { status: 401, error: { code: 'UNAUTHORIZED' } };
}
const user = await db('users').where('id', ctx.req.session.userId).first();
return { data: { id: user.id, name: user.name, role: user.role } };
},
};Vault (Crypto Utilities)
Standalone library for password hashing, ID generation, JWT, and encryption. No framework boot required.
import { vault } from 'arcway';Password Hashing
Uses bcrypt for secure password hashing:
import { vault } from 'arcway';
// Hash a password (default: 10 rounds)
const hash = await vault.hashPassword('my-password');
// Custom rounds (higher = slower + more secure)
const strongHash = await vault.hashPassword('my-password', 12);
// Verify against stored hash
const isValid = await vault.verifyPassword('my-password', hash); // true
const isBad = await vault.verifyPassword('wrong-password', hash); // falseID Generation
import { vault } from 'arcway';
const id = vault.generateNanoId(); // e.g. 'V1StGXR8_Z5jdHi6B-myT' (21 chars, URL-safe)
const short = vault.generateNanoId(12); // Custom length
const uuid = vault.generateUUID(); // e.g. '550e8400-e29b-41d4-a716-446655440000' (RFC 4122)JWT Utilities
ctx.vault signs and verifies with Arcway's managed JWT key derived from your vault master secret. No caller-supplied secret is accepted:
// Create a token
const token = await ctx.vault.jwtEncode(
{ userId: 123, role: 'admin' },
{
expiresIn: '7d', // '1h', '30m', '7d', or seconds as number
issuer: 'my-app', // Optional
audience: 'web', // Optional
algorithm: 'HS256', // Default
},
);
// Verify and decode
const payload = await ctx.vault.jwtDecode(token, {
issuer: 'my-app', // Must match if set during encoding
audience: 'web', // Must match if set during encoding
});
// payload.userId === 123If you need to interoperate with an external JWT issuer or sign with an app-specific key, use jose directly instead of the managed vault helper.
Encryption
Uses AES-256-GCM with scrypt key derivation for strong at-rest encryption:
import { vault } from 'arcway';
const key = process.env.ENCRYPTION_KEY; // Any string (derived via scrypt)
// Encrypt
const encrypted = vault.encrypt('sensitive data', key);
// Returns: 'salt:iv:authTag:ciphertext' (all hex-encoded)
// Decrypt
const decrypted = vault.decrypt(encrypted, key);
// Returns: 'sensitive data'Each encryption generates a random 32-byte salt and 16-byte IV, so encrypting the same plaintext twice produces different ciphertexts.