Session Limits Feature
Overview
The Session Limits feature in Baasix provides administrators with fine-grained control over user sessions across different device types and tenants. This feature allows you to:
- Limit the number of concurrent sessions per user per session type (mobile, web)
- Configure different limits for different tenants in multi-tenant mode
- Block specific session types entirely by setting limits to 0
- Maintain unlimited default sessions for backward compatibility
Key Concepts
Session Types
Baasix supports three session types:
default- Traditional sessions, unlimited by design for backward compatibilitymobile- Sessions from mobile applicationsweb- Sessions from web applications
Session Limit Enforcement
- Session limits are enforced only for
mobileandwebsession types defaultsessions are always allowed regardless of configured limits- Limits are checked during login, registration, magic link authentication, and tenant switching
- When a limit is reached, new logins of that type are blocked with a descriptive error message
Configuration
Session limits are configured through the baasix_Settings table using the metadata field:
{
"mobile_session_limit": 2,
"web_session_limit": 5
}Setting Session Limits
Global Settings (Non-Multi-Tenant)
// Set global session limits
await SettingsModel.create({
tenant_Id: null,
project_name: "My Project",
metadata: {
mobile_session_limit: 1, // Allow only 1 mobile session per user
web_session_limit: 3 // Allow up to 3 web sessions per user
}
});Tenant-Specific Settings (Multi-Tenant Mode)
// Set session limits for a specific tenant
await SettingsModel.create({
tenant_Id: tenantId,
project_name: "Tenant Project",
metadata: {
mobile_session_limit: 2,
web_session_limit: 0 // Block all web sessions for this tenant
}
});Special Values
undefinedornull- No limit (unlimited sessions)0- Block all sessions of this type- Positive integer - Maximum number of concurrent sessions allowed
API Integration
Login with Session Type
Include the authType parameter in your login requests:
// Mobile login
const response = await fetch('/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
password: 'password123',
authType: 'mobile' // Specify session type
})
});Registration with Session Type
// Mobile registration
const response = await fetch('/auth/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
password: 'password123',
firstName: 'John',
lastName: 'Doe',
authType: 'mobile'
})
});Magic Link Authentication
// Request magic link with session type
const response = await fetch('/auth/magiclink', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
link: 'https://myapp.com',
authType: 'web'
})
});Tenant Switching with Session Type
// Switch tenant with session type validation
const response = await fetch('/auth/switch-tenant', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
tenant_Id: 'tenant-uuid',
authType: 'mobile'
})
});Implementation Details
Validation Logic
The session validation logic is implemented in baasix/utils/auth.js:validateSessionLimits():
- Skip validation for
defaultsession types - Validate session type - must be
mobileorweb - Retrieve settings - tenant-specific settings take precedence over global settings
- Check limits - compare active sessions count against configured limit
- Return validation result with appropriate error messages
Database Schema
Sessions are stored in the baasix_Sessions table with the following relevant fields:
CREATE TABLE baasix_Sessions (
id UUID PRIMARY KEY,
token VARCHAR(255) UNIQUE NOT NULL,
user_Id UUID REFERENCES baasix_User(id),
type VARCHAR(50) DEFAULT 'default', -- Session type
expiresAt TIMESTAMP NOT NULL,
createdAt TIMESTAMP DEFAULT NOW(),
updatedAt TIMESTAMP DEFAULT NOW()
);Active Session Counting
Active sessions are counted using:
const activeSessions = await SessionModel.findAll({
where: {
user_Id: userId,
type: sessionType,
expiresAt: {
[Op.gt]: new Date() // Only non-expired sessions
}
}
});Error Handling
Common Error Responses
Session Limit Reached
{
"message": "Maximum mobile session limit (2) reached. Please logout from another device."
}Sessions Blocked
{
"message": "Mobile sessions are not allowed"
}Invalid Session Type
{
"message": "Invalid session type. Must be 'mobile' or 'web'"
}Error Recovery
When users encounter session limit errors, they have several options:
- Logout from other devices - Free up session slots
- Use default session type - Not subject to limits
- Contact administrator - To adjust limits if needed
Multi-Tenant Behavior
Settings Priority
In multi-tenant mode, settings are resolved in this order:
- Tenant-specific settings - If
tenant_Idmatches the user's tenant - Global settings - If no tenant-specific settings exist (
tenant_Id: null) - No limits - If no settings are found
Tenant Isolation
Session limits are enforced per tenant:
- Users with roles in multiple tenants have separate session counts per tenant
- Switching tenants may create new sessions subject to the target tenant's limits
- Session limits only apply to tenant-specific roles
Use Cases
Mobile App Restriction
// Allow only 1 mobile session per user (single device)
{
"mobile_session_limit": 1,
"web_session_limit": null // Unlimited web sessions
}Enterprise Security
// Strict limits for enterprise tenant
{
"mobile_session_limit": 2,
"web_session_limit": 1
}Blocking Device Types
// Block mobile access entirely
{
"mobile_session_limit": 0,
"web_session_limit": 5
}Development Environment
// No limits for development
{
"mobile_session_limit": null,
"web_session_limit": null
}Testing
The feature includes comprehensive test coverage:
Session Type Tests (test/session-types.test.js)
- Default session creation
- Mobile/web session creation
- Invalid session type rejection
- Session limit enforcement
- Zero limit blocking
- Default session bypass
Multi-Tenant Tests (test/switch-tenant-session-limits.test.js)
- Tenant switching with limits
- Cross-tenant session isolation
- Tenant-specific limit configuration
Running Tests
cd api/
npm test -- session-types.test.js
npm test -- switch-tenant-session-limits.test.jsBest Practices
Limit Configuration
- Start with reasonable limits - Consider user workflows
- Monitor usage patterns - Adjust limits based on real usage
- Communicate limits - Let users know about session restrictions
Error Handling
- Provide clear messages - Help users understand what to do
- Offer alternatives - Suggest logout or contact support
- Log limit violations - Monitor for potential abuse
Security Considerations
- Regular cleanup - Expired sessions are automatically cleaned
- Audit sessions - Monitor active sessions per user
- Adjust for risk - Stricter limits for sensitive applications
Monitoring and Analytics
Session Metrics
Track these metrics for insights:
- Active sessions per user per type
- Session limit violations per tenant
- Peak concurrent sessions
- Average session duration by type
Database Queries
-- Count active sessions by type
SELECT type, COUNT(*) as active_count
FROM baasix_Sessions
WHERE expiresAt > NOW()
GROUP BY type;
-- Users hitting session limits
SELECT user_Id, type, COUNT(*) as session_count
FROM baasix_Sessions
WHERE expiresAt > NOW()
GROUP BY user_Id, type
HAVING COUNT(*) >= (
SELECT CAST(metadata->>'mobile_session_limit' AS INTEGER)
FROM baasix_Settings
WHERE tenant_Id IS NULL
);Troubleshooting
Common Issues
-
"Session limit reached" but user has no active sessions
- Check for expired sessions not yet cleaned up
- Verify session cleanup job is running
-
Limits not being enforced
- Verify settings are properly configured
- Check that
authTypeis being passed in requests
-
Multi-tenant limits not working
- Ensure tenant-specific settings exist
- Verify user has tenant-specific roles
Debug Information
Enable debug logging to troubleshoot:
// In validateSessionLimits function
console.log('Session validation:', {
userId,
sessionType,
tenantId,
activeSessions: activeSessions.length,
sessionLimit,
isValid: activeSessions.length < sessionLimit
});Migration Notes
Upgrading Existing Installations
When upgrading to include session limits:
- Existing sessions continue to work (marked as
defaulttype) - No immediate impact on current users
- Configure limits gradually - Start with high limits and reduce
- Update client applications to pass
authTypeparameter
Database Migration
The type field in baasix_Sessions defaults to 'default' for backward compatibility. No data migration is required.
API Reference
POST /auth/login
Parameters:
authType(optional):'mobile'|'web'|'default'
POST /auth/register
Parameters:
authType(optional):'mobile'|'web'|'default'
POST /auth/magiclink
Parameters:
authType(optional):'mobile'|'web'|'default'
POST /auth/switch-tenant
Parameters:
authType(optional):'mobile'|'web'|'default'
All endpoints return standard authentication responses with session limit validation applied when authType is specified and not 'default'.
See also
- Authentication Routes - Endpoints and usage for auth, login, register
- Settings Routes - Configure global and tenant settings for session limits
- Multi-tenant Guide - How tenant-specific settings and isolation work
- Error Handling Guide - Handling authentication and session errors gracefully
- Integration Guide - Client-side considerations and passing
authType