Kynetra FX

Documentation

Cookies & Headers

Kynetra FX provides ctx.cookie(name) to read request cookies and ctx.setCookie(name, value, opts?) to write response cookies. Request headers are read with ctx.header(name) and response headers are written with ctx.set(name, value).

Reading request cookies#

ctx.cookie(name) parses the incoming Cookie request header and returns the value of the named cookie as a string, or null if absent.

app.ts
import { createFX } from '@kynetra/fx'
 
const app = createFX()
 
app.get('/me', (ctx) => {
const sessionId = ctx.cookie('session') // string | null
if (!sessionId) {
return ctx.json({ error: 'not logged in' }, { status: 401 })
}
return ctx.json({ sessionId })
})

Setting response cookies#

ctx.setCookie(name, value, opts?) adds a Set-Cookie header to the outgoing response. Call it before returning a response from the handler.

app.ts
app.post('/login', async (ctx) => {
const { username, password } = await ctx.jsonBody()
 
// Authenticate (pseudo-code)
const sessionId = await createSession(username, password)
 
ctx.setCookie('session', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'Lax',
path: '/',
maxAge: 60 * 60 * 24 * 7, // 1 week in seconds
})
 
return ctx.json({ ok: true })
})
NameTypeDescription
httpOnlybooleanPrevents JavaScript access via document.cookie. Recommended for session cookies.
securebooleanSend only over HTTPS. Always set in production.
sameSite'Strict' | 'Lax' | 'None'Cross-site request policy. Use Lax for most session cookies; None requires Secure.
pathstringCookie path scope. Defaults to '/'.
domainstringCookie domain scope. Omit to scope to the exact host.
maxAgenumberLifetime in seconds from now. Takes precedence over expires.
expiresDateAbsolute expiry date. Use maxAge instead for most cases.

Deleting cookies#

To delete a cookie, set it with maxAge: 0 (or a past expiry). The browser will immediately discard it.

app.ts
app.post('/logout', (ctx) => {
ctx.setCookie('session', '', {
httpOnly: true,
secure: true,
path: '/',
maxAge: 0,
})
return ctx.json({ ok: true })
})

Multiple cookies#

Call ctx.setCookie() multiple times to set multiple cookies. Each call appends a new Set-Cookie header.

app.ts
app.post('/setup', (ctx) => {
ctx.setCookie('theme', 'dark', { path: '/', maxAge: 86400 * 365 })
ctx.setCookie('lang', 'en', { path: '/', maxAge: 86400 * 365 })
return ctx.json({ ok: true })
})

Request headers#

ctx.header(name) returns a single request header value (case-insensitive) or null if absent. For multiple values, access ctx.req.headers directly — it is a standard Headers object.

app.ts
app.get('/info', (ctx) => {
const auth = ctx.header('authorization')
const ct = ctx.header('content-type')
const tenant = ctx.header('x-tenant-id')
 
// Standard Headers API for multi-value or iteration
const all: Record<string, string> = {}
ctx.req.headers.forEach((v, k) => { all[k] = v })
 
return ctx.json({ auth, ct, tenant, all })
})

Response headers#

Use ctx.set(name, value) to set a single response header and ctx.append(name, value) to append to an existing one. You can also pass headers in the init object of any response helper.

app.ts
// Via ctx.set()
app.get('/data', (ctx) => {
ctx.set('Cache-Control', 'public, max-age=300')
ctx.set('X-Powered-By', 'Kynetra FX')
return ctx.json({ value: 42 })
})
 
// Via init object
app.get('/nocache', (ctx) =>
ctx.json({ ts: Date.now() }, {
headers: { 'Cache-Control': 'no-store' },
})
)
 
// Append Vary header in middleware
app.use(async (ctx, next) => {
const res = await next()
ctx.append('Vary', 'Accept-Encoding')
return res
})

Session auth with cookies#

For full session-based authentication including signed cookie JWT sessions, see the Auth page. The sessionAuth() strategy from @kynetra/fx-auth handles signing and verification automatically.

app.ts
import { createFX } from '@kynetra/fx'
import { sessionAuth, signSession, requireAuth } from '@kynetra/fx-auth'
 
const app = createFX()
const SESSION_SECRET = 'my-32-char-or-longer-secret-key!'
 
app.post('/login', async (ctx) => {
// Verify credentials (pseudo-code)...
const token = await signSession({ sub: 'user-42', roles: ['member'] }, SESSION_SECRET)
 
ctx.setCookie('session', token, {
httpOnly: true,
secure: true,
sameSite: 'Lax',
path: '/',
maxAge: 86400 * 7,
})
 
return ctx.json({ ok: true })
})
 
const strategy = sessionAuth({ secret: SESSION_SECRET })
 
app.get('/me', requireAuth([strategy]), (ctx) => {
return ctx.json({ ok: true })
})

Note

Always set httpOnly: true and secure: true for session cookies in production. Omitting these is a common security mistake.