session
A session management library for JavaScript. This package provides a flexible and secure way to manage user sessions in server-side applications with a flexible API for different session storage strategies.
Installation
Core API
Session
A session persists data for a specific user across multiple requests to a server.
import { createSession } from 'remix/session'
let session = createSession ()
session . set ( 'userId' , '123' )
session . set ( 'count' , 1 )
let userId = session . get ( 'userId' ) // '123'
let count = session . get ( 'count' ) // 1
Properties
The unique identifier for this session
The raw session data in a format suitable for storage. Note: Do not use this for normal reading of session data. Use the get method instead.
Whether this session has been modified since it was created
Whether this session has been destroyed
The session ID that will be deleted when the session is saved. This is set to the original session ID when the session ID is regenerated with the deleteOldSession option.
The number of key/value pairs in the session
Methods
get
Get a value from the session.
let userId = session . get ( 'userId' )
The key of the value to get
The value for the given key, or undefined if the key doesn’t exist
set
Set a value in the session.
session . set ( 'userId' , '123' )
session . set ( 'preferences' , { theme: 'dark' })
The key of the value to set
The value to set. Pass null or undefined to remove the key.
has
Check if a value is stored for the given key.
if ( session . has ( 'userId' )) {
console . log ( 'User is logged in' )
}
true if a value is stored for the given key, false otherwise
unset
Remove a value from the session.
The key of the value to remove
flash
Set a value in the session that will be available only during the next request.
session . flash ( 'message' , 'User created successfully!' )
session . flash ( 'error' , 'Invalid credentials' )
The key of the value to flash
regenerateId
Regenerate the session ID while preserving the session data. This should be called after login or other privilege changes to prevent session fixation attacks.
// After successful login
session . set ( 'userId' , user . id )
session . regenerateId ( true ) // Delete old session
Whether to delete the old session data when the session is saved
destroy
Mark this session as destroyed. This prevents all further modifications to the session.
// On logout
session . destroy ()
createSession
Create a new session.
import { createSession } from 'remix/session'
let session = createSession ()
let sessionWithId = createSession ( 'custom-id' )
let sessionWithData = createSession ( 'id' , [{ userId: '123' }, { message: 'Welcome!' }])
The ID of the session. If not provided, a new cryptographically secure session ID will be generated.
The initial data for the session in the format [valueData, flashData]
createSessionId
Create a new cryptographically secure session ID.
import { createSessionId } from 'remix/session'
let id = createSessionId () // e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
A new session ID (UUID v4)
Storage Strategies
SessionStorage
An interface for storing and retrieving session data.
interface SessionStorage {
read ( cookie : string | null ) : Promise < Session >
save ( session : Session ) : Promise < string | null >
}
read
(cookie: string | null) => Promise<Session>
Retrieve a new session from storage based on the session cookie
save
(session: Session) => Promise<string | null>
Save session data in storage and return the session cookie. Returns null if no session cookie should be set.
createCookieSessionStorage
Creates a session storage that stores all session data in the session cookie itself.
import { createCookieSessionStorage } from 'remix/session/cookie-storage'
let storage = createCookieSessionStorage ()
let session = await storage . read ( cookieValue )
session . set ( 'count' , 1 )
let cookie = await storage . save ( session )
Note: This is suitable for production. However, the total size of the session cookie is limited to the browser’s maximum cookie size, typically 4096 bytes.
A session storage that stores data in cookies
createMemorySessionStorage
Creates a session storage that stores all session data in memory.
import { createMemorySessionStorage } from 'remix/session/memory-storage'
let storage = createMemorySessionStorage ()
let session = await storage . read ( cookieValue )
session . set ( 'count' , 1 )
let cookie = await storage . save ( session )
Note: This is useful for testing and development. All session data is lost when the server restarts.
options
MemorySessionStorageOptions
Optional configuration Whether to reuse session IDs sent from the client that are not found in storage
A session storage that stores data in memory
createFsSessionStorage
Creates a session storage that stores session data in the filesystem.
import { createFsSessionStorage } from 'remix/session/fs-storage'
let storage = createFsSessionStorage ( '/tmp/sessions' )
let session = await storage . read ( cookieValue )
session . set ( 'count' , 1 )
let cookie = await storage . save ( session )
Note: This is a good choice for production environments. It requires access to a persistent filesystem.
The directory where session files will be stored
A session storage that stores data in the filesystem
Examples
Basic Session Management
import { createCookieSessionStorage } from 'remix/session/cookie-storage'
let storage = createCookieSessionStorage ()
async function handleRequest ( cookie : string | null ) {
let session = await storage . read ( cookie )
session . set ( 'count' , Number ( session . get ( 'count' ) ?? 0 ) + 1 )
return {
session ,
cookie: await storage . save ( session ),
}
}
let response1 = await handleRequest ( null )
console . log ( response1 . session . get ( 'count' )) // 1
let response2 = await handleRequest ( response1 . cookie )
console . log ( response2 . session . get ( 'count' )) // 2
Flash Messages
import { createMemorySessionStorage } from 'remix/session/memory-storage'
let storage = createMemorySessionStorage ()
async function requestIndex ( cookie : string | null ) {
let session = await storage . read ( cookie )
return { session , cookie: await storage . save ( session ) }
}
async function requestSubmit ( cookie : string | null ) {
let session = await storage . read ( cookie )
session . flash ( 'message' , 'success!' )
return { session , cookie: await storage . save ( session ) }
}
// Flash data is undefined on the first request
let response1 = await requestIndex ( null )
console . log ( response1 . session . get ( 'message' )) // undefined
// Flash data is undefined on the same request it is set
let response2 = await requestSubmit ( response1 . cookie )
console . log ( response2 . session . get ( 'message' )) // undefined
// Flash data is available on the next request
let response3 = await requestIndex ( response2 . cookie )
console . log ( response3 . session . get ( 'message' )) // 'success!'
// Flash data is not available on subsequent requests
let response4 = await requestIndex ( response3 . cookie )
console . log ( response4 . session . get ( 'message' )) // undefined
Session Security: Regenerating IDs
import { createFsSessionStorage } from 'remix/session/fs-storage'
let sessionStorage = createFsSessionStorage ( '/tmp/sessions' )
async function requestLogin ( cookie : string | null ) {
let session = await sessionStorage . read ( cookie )
// Verify credentials...
session . set ( 'userId' , 'mj' )
// Regenerate session ID after privilege change
session . regenerateId ( true ) // true = delete old session
return { session , cookie: await sessionStorage . save ( session ) }
}
let response = await requestLogin ( null )
console . log ( response . session . get ( 'userId' )) // 'mj'
User Authentication Flow
import { createCookieSessionStorage } from 'remix/session/cookie-storage'
let storage = createCookieSessionStorage ()
// Login handler
async function login ( cookie : string | null , credentials : { username : string ; password : string }) {
let session = await storage . read ( cookie )
// Verify credentials
let user = await verifyCredentials ( credentials )
if ( ! user ) {
session . flash ( 'error' , 'Invalid credentials' )
return { session , cookie: await storage . save ( session ) }
}
// Set user data and regenerate session ID for security
session . set ( 'userId' , user . id )
session . set ( 'username' , user . username )
session . regenerateId ( true )
session . flash ( 'message' , 'Login successful!' )
return { session , cookie: await storage . save ( session ) }
}
// Logout handler
async function logout ( cookie : string | null ) {
let session = await storage . read ( cookie )
session . destroy ()
return { cookie: await storage . save ( session ) }
}
// Protected route
async function getProfile ( cookie : string | null ) {
let session = await storage . read ( cookie )
let userId = session . get ( 'userId' )
if ( ! userId ) {
return { error: 'Unauthorized' , status: 401 }
}
let user = await getUserById ( userId )
return { user , cookie: await storage . save ( session ) }
}
TypeScript: Typed Sessions
import { createSession , type Session } from 'remix/session'
interface UserData {
userId : string
username : string
role : 'admin' | 'user'
}
interface FlashData {
message : string
error : string
}
let session = createSession < UserData , FlashData >()
// Type-safe access
session . set ( 'userId' , '123' )
session . set ( 'role' , 'admin' )
session . flash ( 'message' , 'Welcome!' )
let userId : string | undefined = session . get ( 'userId' )
let role : 'admin' | 'user' | undefined = session . get ( 'role' )