Arcwayv0.3.0

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.sessionEffect
{ userId: 1 }Seals data, sets Set-Cookie header
nullClears 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); // false

ID 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 === 123

If 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.

On this page