Quick Start: Using Explicit Config in flarelette-demo¶
Problem Solved¶
Previously, using flarelette-jwt in the flarelette-demo required:
- Setting up
.dev.varsfiles - Using
bindEnv()middleware to set global state - Complex Miniflare configurations
- Dealing with
globalThis.__FLARELETTE_ENVpollution
With the new explicit configuration API, none of this is required!
Gateway Integration¶
Step 1: Create JWT Config at Startup¶
In workers/gateway/src/index.ts:
import { createHS512Config, type HS512Config } from '@chrislyons-dev/flarelette-jwt'
// Create config once at app startup
function createJwtConfig(env: Env): HS512Config {
return createHS512Config(env.JWT_SECRET, {
iss: 'http://localhost:8787',
aud: ['http://localhost:8788', 'http://localhost:8789', 'http://localhost:8790'],
ttlSeconds: 900, // 15 minutes
})
}
// Store config in app context
app.use('*', async (c, next) => {
c.set('jwtConfig', createJwtConfig(c.env))
await next()
})
Step 2: Update Token Minting in auth.ts¶
Replace the complex environment-based code:
// OLD - Complex environment setup
import { sign } from '@chrislyons-dev/flarelette-jwt'
import { bindEnv } from '@chrislyons-dev/flarelette-jwt/adapters'
// Required bindEnv() middleware
app.use('*', (c, next) => {
bindEnv(c.env)
return next()
})
// Still reads from global state
const token = await sign({ sub: 'user123' })
With simple, explicit code:
// NEW - Explicit and clean
import { signWithConfig } from '@chrislyons-dev/flarelette-jwt'
export async function mintInternalToken(c: Context, claims: JwtPayload) {
const config = c.get('jwtConfig') // Get from context
return await signWithConfig(claims, config)
}
// Usage in endpoint
app.post('/auth/token', async c => {
const externalToken = c.req.header('Authorization')
const externalPayload = await verifyAuth0Token(externalToken)
// Mint internal token with explicit config
const token = await mintInternalToken(c, {
sub: externalPayload.sub,
email: externalPayload.email,
permissions: externalPayload.permissions,
})
return c.json({ token })
})
Backend Service Integration¶
Step 3: Verify Tokens in Backend Services¶
In workers/content-service/src/index.ts:
import { verifyWithConfig, createHS512Config } from '@chrislyons-dev/flarelette-jwt'
// Create config at startup
const jwtConfig = createHS512Config(env.JWT_SECRET, {
iss: 'http://localhost:8787',
aud: 'http://localhost:8788', // This service's URL
})
// Middleware to verify tokens
app.use('*', async (c, next) => {
const authHeader = c.req.header('Authorization')
if (!authHeader?.startsWith('Bearer ')) {
return c.json({ error: 'Unauthorized' }, 401)
}
const token = authHeader.slice(7)
const payload = await verifyWithConfig(token, jwtConfig)
if (!payload) {
return c.json({ error: 'Invalid token' }, 401)
}
c.set('user', payload)
await next()
})
Development Environment Setup¶
No .dev.vars Required¶
Create a shared config for all services:
// dev-config.ts (shared across all workers)
import { type HS512Config } from '@chrislyons-dev/flarelette-jwt'
// Simple dev secret - same for all services
const DEV_SECRET = Buffer.alloc(32, 42) // 32 bytes, all set to 42
export const DEV_JWT_CONFIG: HS512Config = {
alg: 'HS512',
secret: DEV_SECRET,
iss: 'http://localhost:8787',
aud: ['http://localhost:8788', 'http://localhost:8789', 'http://localhost:8790'],
ttlSeconds: 3600, // 1 hour for dev
}
Use in all services:
import { signWithConfig, verifyWithConfig } from '@chrislyons-dev/flarelette-jwt'
import { DEV_JWT_CONFIG } from './dev-config'
// Gateway
const token = await signWithConfig(claims, DEV_JWT_CONFIG)
// Backend services
const payload = await verifyWithConfig(token, DEV_JWT_CONFIG)
Testing¶
Write tests without any environment setup:
import { describe, it, expect } from 'vitest'
import { signWithConfig, verifyWithConfig } from '@chrislyons-dev/flarelette-jwt'
describe('Gateway JWT minting', () => {
const testConfig = {
alg: 'HS512' as const,
secret: new Uint8Array(32),
iss: 'test-gateway',
aud: 'test-service',
}
it('should mint valid token', async () => {
const token = await signWithConfig({ sub: 'user123' }, testConfig)
const payload = await verifyWithConfig(token, testConfig)
expect(payload?.sub).toBe('user123')
})
})
Migration Checklist¶
- Update gateway to use
createHS512Config() - Replace
sign()withsignWithConfig() - Update backend services to use
verifyWithConfig() - Remove
bindEnv()middleware calls - Simplify
.dev.varsfiles (just needJWT_SECRETnow) - Remove custom Miniflare scripts (can use
wrangler devdirectly) - Update tests to use explicit config
- Remove environment variable setup from tests
Benefits for flarelette-demo¶
- Simpler development - No complex environment setup
- Faster startup - No need to configure bindings
- Better testing - Isolated, reproducible tests
- Clearer code - Explicit configuration is self-documenting
- Easier debugging - No hidden global state
- Multiple configs - Can test different scenarios easily
Example: Complete Gateway Setup¶
// workers/gateway/src/index.ts
import { Hono } from 'hono'
import {
signWithConfig,
createHS512Config,
type HS512Config,
} from '@chrislyons-dev/flarelette-jwt'
type Env = {
JWT_SECRET: string
}
const app = new Hono<{ Bindings: Env; Variables: { jwtConfig: HS512Config } }>()
// Create config middleware
app.use('*', async (c, next) => {
const config = createHS512Config(c.env.JWT_SECRET, {
iss: 'http://localhost:8787',
aud: ['http://localhost:8788', 'http://localhost:8789'],
ttlSeconds: 900,
})
c.set('jwtConfig', config)
await next()
})
// Auth endpoint
app.post('/auth/token', async c => {
const config = c.get('jwtConfig')
// Verify external token (Auth0, etc.)
const externalToken = c.req.header('Authorization')?.slice(7)
const externalPayload = await verifyAuth0Token(externalToken)
// Mint internal token
const token = await signWithConfig(
{
sub: externalPayload.sub,
email: externalPayload.email,
permissions: externalPayload.permissions,
},
config
)
return c.json({ token })
})
export default app
Next Steps¶
- Install updated flarelette-jwt-kit:
npm install @chrislyons-dev/flarelette-jwt@latest - Update gateway auth.ts to use explicit config
- Update backend services to use explicit config
- Remove bindEnv() middleware
- Simplify development environment
- Run tests to verify everything works
The explicit configuration API makes flarelette-jwt-kit as simple to use as direct Web Crypto API, but with all the benefits of the library's features (delegation, policies, EdDSA support, etc.).