/** * MWT / JWT token tests — decode round-trip + cross-language byte-parity pins * against the live Python mint (`cores/mizan-python`). */ import { describe, test, expect } from 'bun:test' import { createHmac, createHash } from 'crypto' import { execFileSync } from 'child_process' import { existsSync } from 'fs' import { resolve } from 'path' import { decodeMwt, decodeJwtBearer, identityFromMwt, signMwt, computePermissionKey, createAccessToken, createRefreshToken, type MintUser, } from '../src' function b64url(buf: Buffer | string): string { return Buffer.from(buf).toString('base64url') } /** Mint an HS256 MWT with node crypto, mirroring Python create_mwt. */ function mint(payload: Record, secret: string, kid = 'v1'): string { const header = b64url(JSON.stringify({ alg: 'HS256', kid, typ: 'JWT' })) const body = b64url(JSON.stringify(payload)) const sig = createHmac('sha256', secret).update(`${header}.${body}`).digest('base64url') return `${header}.${body}.${sig}` } const SECRET = 'round-trip-secret' const now = Math.floor(Date.now() / 1000) function basePayload(overrides: Record = {}) { return { sub: '7', staff: true, super: false, pkey: 'abc123', aud: 'mizan', iat: now, nbf: now, exp: now + 300, ...overrides, } } describe('MWT round-trip', () => { test('valid token decodes', () => { const token = mint(basePayload(), SECRET) const p = decodeMwt(token, SECRET) expect(p).not.toBeNull() expect(p!.sub).toBe('7') expect(p!.staff).toBe(true) expect(p!.super).toBe(false) expect(p!.pkey).toBe('abc123') expect(p!.kid).toBe('v1') expect(p!.aud).toBe('mizan') }) test('identityFromMwt maps claims', () => { const token = mint(basePayload({ sub: '99', staff: false, super: true }), SECRET) const p = decodeMwt(token, SECRET)! expect(identityFromMwt(p)).toEqual({ isAuthenticated: true, isStaff: false, isSuperuser: true, id: 99, }) }) test('decodeJwtBearer strips Bearer prefix', () => { const token = mint(basePayload(), SECRET) const p = decodeJwtBearer(`Bearer ${token}`, SECRET) expect(p).not.toBeNull() expect(p!.sub).toBe('7') }) test('null on tampered signature', () => { const token = mint(basePayload(), SECRET) const tampered = token.slice(0, -2) + (token.endsWith('AA') ? 'BB' : 'AA') expect(decodeMwt(tampered, SECRET)).toBeNull() }) test('null on wrong secret', () => { const token = mint(basePayload(), SECRET) expect(decodeMwt(token, 'other-secret')).toBeNull() }) test('null on expired exp', () => { const token = mint(basePayload({ exp: now - 10 }), SECRET) expect(decodeMwt(token, SECRET)).toBeNull() }) test('null on future nbf', () => { const token = mint(basePayload({ nbf: now + 1000 }), SECRET) expect(decodeMwt(token, SECRET)).toBeNull() }) test('null on wrong aud', () => { const token = mint(basePayload({ aud: 'other' }), SECRET) expect(decodeMwt(token, SECRET)).toBeNull() }) test('null on malformed token', () => { expect(decodeMwt('not.a.jwt', SECRET)).toBeNull() expect(decodeMwt('onlyonepart', SECRET)).toBeNull() expect(decodeMwt('', SECRET)).toBeNull() }) }) describe('MWT cross-language pin (Python create_mwt)', () => { const TOKEN = 'eyJhbGciOiJIUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJzdWIiOiI0MiIsInN0YWZmIjp0cnVlLCJzdXBlciI6ZmFsc2UsInBrZXkiOiIwZTk5OGE5ZmYxNjkwNDYzN2EwM2QyZWEwZmJkYmY5NzQyOTdhOWQxYTVkMjViOGQ0Mjk0ZmE4ODIxMTVlNDU3IiwiYXVkIjoibWl6YW4iLCJpYXQiOjE3MDAwMDAwMDAsIm5iZiI6MTcwMDAwMDAwMCwiZXhwIjo0MTAyNDQ0ODAwfQ._V92JXiLSLXoyuSwbNvvJjwzgmczmC7dvX34kVSLIa8' const PIN_SECRET = 'pin-test-secret-mwt' test('decodes the Python-minted token', () => { const p = decodeMwt(TOKEN, PIN_SECRET) expect(p).not.toBeNull() expect(p!.sub).toBe('42') expect(p!.staff).toBe(true) expect(p!.super).toBe(false) expect(p!.pkey).toBe('0e998a9ff16904637a03d2ea0fbdbf974297a9d1a5d25b8d4294fa882115e457') expect(p!.kid).toBe('v1') expect(p!.aud).toBe('mizan') }) test('identity from Python-minted token', () => { const p = decodeMwt(TOKEN, PIN_SECRET)! expect(identityFromMwt(p)).toEqual({ isAuthenticated: true, isStaff: true, isSuperuser: false, id: 42, }) }) }) // ─── Mint: round-trip + cross-language byte-parity ──────────────────────────── const REPO_ROOT = resolve(import.meta.dir, '../../..') const MIZAN_PYTHON = resolve(REPO_ROOT, 'cores/mizan-python') const UV_AVAILABLE = (() => { try { execFileSync('uv', ['--version'], { stdio: 'ignore' }) return existsSync(resolve(MIZAN_PYTHON, 'pyproject.toml')) } catch { return false } })() /** * Run a Python snippet against cores/mizan-python and return stdout (trimmed). * `time.time` is pinned so the production mint functions are deterministic. */ function py(snippet: string): string { return execFileSync('uv', ['run', '--project', MIZAN_PYTHON, 'python', '-c', snippet], { encoding: 'utf-8', }).trim() } describe('MWT mint — round-trip', () => { const SECRET = 'mint-roundtrip-secret' test('signMwt produces a token decodeMwt accepts', () => { const user: MintUser = { pk: 7, isStaff: true, isSuperuser: false, permissions: ['a.view', 'a.edit'] } const token = signMwt(user, SECRET, { now: Math.floor(Date.now() / 1000) }) const p = decodeMwt(token, SECRET) expect(p).not.toBeNull() expect(p!.sub).toBe('7') expect(p!.staff).toBe(true) expect(p!.super).toBe(false) expect(p!.kid).toBe('v1') expect(p!.aud).toBe('mizan') // pkey is the permission hash, surviving the round-trip. expect(p!.pkey).toBe(computePermissionKey(user)) }) test('computePermissionKey matches the documented blob hash', () => { const user: MintUser = { pk: 1, isStaff: true, isSuperuser: false, permissions: ['z', 'a'] } // "1:0:a,z" — staff:super:sorted-perms. const expected = createHash('sha256').update('1:0:a,z', 'utf-8').digest('hex') expect(computePermissionKey(user)).toBe(expected) }) }) describe('MWT mint — cross-language pin (Python create_mwt)', () => { const SECRET = 'pin-mint-secret-mwt' const NOW = 1700000000 test.skipIf(!UV_AVAILABLE)('TS signMwt byte-identical to Python create_mwt', () => { const user: MintUser = { pk: 42, isStaff: true, isSuperuser: false, permissions: ['app.view_thing', 'app.change_thing'], } const tsToken = signMwt(user, SECRET, { ttl: 300, now: NOW }) // Drive the REAL create_mwt with time.time pinned to NOW and a // user stub whose get_all_permissions returns the same perms. const pyToken = py(String.raw` import time, sys time.time = lambda: ${NOW} from mizan_core.mwt import create_mwt class U: pk = 42 is_staff = True is_superuser = False def get_all_permissions(self): return {"app.view_thing", "app.change_thing"} sys.stdout.write(create_mwt(U(), ${JSON.stringify(SECRET)}, ttl=300)) `) expect(tsToken).toBe(pyToken) }) }) describe('JWT mint — cross-language pin (Python create_access/refresh_token)', () => { const SECRET = 'pin-mint-secret-jwt' const NOW = 1700000000 const config = { privateKey: SECRET, accessTokenExpiresIn: 300, refreshTokenExpiresIn: 604800 } const claims = { userId: 42, sessionKey: 'sess-abc', isStaff: true, isSuperuser: false } test.skipIf(!UV_AVAILABLE)('TS createAccessToken byte-identical to Python', () => { const tsToken = createAccessToken(claims, config, NOW) const pyToken = py(String.raw` import time, sys time.time = lambda: ${NOW} from mizan_core.auth.jwt import JWTConfig, create_access_token cfg = JWTConfig(private_key=${JSON.stringify(SECRET)}, public_key=${JSON.stringify(SECRET)}) sys.stdout.write(create_access_token(42, "sess-abc", cfg, is_staff=True, is_superuser=False)) `) expect(tsToken).toBe(pyToken) }) test.skipIf(!UV_AVAILABLE)('TS createRefreshToken byte-identical to Python', () => { const tsToken = createRefreshToken(claims, config, NOW) const pyToken = py(String.raw` import time, sys time.time = lambda: ${NOW} from mizan_core.auth.jwt import JWTConfig, create_refresh_token cfg = JWTConfig(private_key=${JSON.stringify(SECRET)}, public_key=${JSON.stringify(SECRET)}) sys.stdout.write(create_refresh_token(42, "sess-abc", cfg, is_staff=True, is_superuser=False)) `) expect(tsToken).toBe(pyToken) }) })