@aisonren/farrow-session v1.1.1
farrow-session
A session middleware for Farrow framework, providing flexible and decoupled session management.
Features
- 🔌 Decoupled Design: Separate parser and store implementations
- 🛠 Flexible Configuration: Support multiple middleware instances
- 🔒 Customizable Security: Support custom authentication mechanisms
- 🍪 Cookie Support: Built-in cookie-based parser and store implementations
- 🎯 Type Safety: Complete TypeScript type support
Design Philosophy
Although named as "farrow-session", this middleware adopts a more flexible design approach:
Decoupled Information Flow and Separation of Concerns
- SessionInfo: Exchange information between client and server (e.g., sessionId, accessToken, refreshToken)
- SessionMeta: Exchange information between Parser and Store (e.g., sessionId/accessToken/refreshToken with expiration time)
- SessionData: Exchange information between Store and Context (server-side only data, like user info, permissions)
Independent Component Design
- SessionParser: Handles parsing and response setting
- SessionStore: Manages session storage and validation
- SessionContext: Controls session lifecycle within requests
Flexible Session Management
- No built-in expiration mechanism, developers can customize expiration logic
- Customizable session validation logic
- Support for various authentication scenarios (Session, JWT, OAuth, etc.)
Multiple Middleware Support
- Support multiple middleware instances, each with different configurations and functionalities
This design makes the middleware adaptable to various authentication scenarios and requirements, such as:
- Traditional server-side session management
- JWT-based authentication and token renewal
- OAuth2 refresh token handling
- Hybrid authentication systems
- Seamless renewal or dynamic session validity management
Type Definitions
Please refer to session.ts and cookie.ts for type definitions and comments
Installation
# npm
npm install @aisonren/farrow-session
# pnpm
pnpm add @aisonren/farrow-session
# yarn
yarn add @aisonren/farrow-session
Usage
Basic Usage (Cookie Implementation)
import { Http } from 'farrow-http'
import { createSessionCtx, cookieSessionParser, cookieSessionStore } from '@aisonren/farrow-session'
// Create session context
const sessionCtx = createSessionCtx<{ userId?: string }>({ userId: undefined })
// Create session parser
const parser = cookieSessionParser({
sessionIdKey: 'sess:id',
cookieOptions: {
maxAge: 24 * 60 * 60 * 1000, // 24 hours, when expiresTime/expireTime exists in sessionMeta passed to parser.set, it will be used as cookie's expires and ignore maxAge
httpOnly: true,
},
})
// Create session store
const store = cookieSessionStore({
sessionStoreKey: 'sess:store',
expiresOptions: {
rolling: true,
time: 24 * 60 * 60 * 1000, // 24 hours, when expiresTime/expireTime exists in sessionMeta passed to parser.set, it will be used as cookie's expires and ignore maxAge
},
cookieOptions: {
maxAge: 24 * 60 * 60 * 1000,
httpOnly: true,
},
})
// Create session middleware
const session = createFarrowSession({
sessionCtx,
sessionParser: parser,
sessionStore: store,
autoSave: true,
})
// Use in Farrow application
const http = Http()
http.use(session)
http.use(() => {
// Get session data
const data = sessionCtx.get()
// Set session data
sessionCtx.set({ userId: '123' })
// Regenerate session ID
await sessionCtx.regenerateId()
// Destroy session
await sessionCtx.destroy()
return Response.json({ success: true })
})
Custom Cookie Session Parser Codec
You can provide custom encoders/decoders for cookieSessionParser:
const parser = cookieSessionParser({
sessionIdKey: 'sess:id',
customCodec: {
encode: (plainSessionId: string) => {
// Custom encoding logic
return Buffer.from(plainSessionId).toString('base64')
},
decode: (encodedSessionId: string) => {
// Custom decoding logic
return Buffer.from(encodedSessionId, 'base64').toString('utf8')
},
},
})
Custom SessionStore
You can provide custom storage implementation for SessionStore:
import { SessionStore } from '@aisonren/farrow-session'
import { Redis } from 'ioredis'
// Example: Redis-based session store
const redisSessionStore: SessionStore = {
async create() {
const sessionId = generateULID()
const sessionData = {}
await redis.set(sessionId, JSON.stringify(sessionData))
return { sessionId, sessionData }
},
async get(sessionId) {
const data = await redis.get(sessionId)
return data ? JSON.parse(data) : undefined
},
async set(sessionId, data) {
await redis.set(sessionId, JSON.stringify(data))
return true
},
async destroy(sessionId) {
await redis.del(sessionId)
return true
},
}
// Example: session store may need get and set the header
import { sessionHeaderCtx } from '@aisonren/farrow-session'
const cookieSessionStore: SessionStore = {
//.....other code
async get(sessionId: string) {
const requestInfo = useRequestInfo()
// ...other code
},
async set(sessionId, sessionData) {
const sessionHeaders = sessionHeaderCtx.get()
// ...other code
sessionHeaderCtx.set([...sessionHeaders, Response.cookie(sessionId, sessionData)])
// ...other code
},
}
Multiple Session Middleware
You can create multiple session middleware instances for different purposes:
// Admin session (with strict security measures)
const adminSession = createFarrowSession({
sessionCtx: adminSessionCtx,
sessionParser: headerSessionParser,
sessionStore: redisSessionStore,
})
// User session (with cookie-based storage)
const userSession = createFarrowSession({
sessionCtx: userSessionCtx,
sessionParser: cookieSessionParser(/* ... */),
sessionStore: cookieSessionStore(/* ... */),
})
// Apply to different routes
http.use('/admin', adminSession)
http.use('/api', userSession)
Security Considerations
The built-in
cookieSessionStore
is provided for development convenience only and is not recommended for storing sensitive data in production. Consider using dedicated session stores (like Redis, MongoDB) for better security.The middleware does not include any default parser or store implementations. You must explicitly choose and configure them based on your security requirements.
Use Cases
Multi-tenant Applications
- Different session stores for different tenants
- Different session expiration strategies, such as:
- Fixed expiration time
- Risk assessment based on user activity
- Custom session data structures
Mixed Authentication Systems
- API tokens for mobile clients
- Cookie-based sessions for web clients
- OAuth tokens for third-party applications
Microservices Architecture
- Distributed session storage
- Service-specific session configurations
- Cross-service session sharing
License
MIT