BaasixBaasix

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:

  1. default - Traditional sessions, unlimited by design for backward compatibility
  2. mobile - Sessions from mobile applications
  3. web - Sessions from web applications

Session Limit Enforcement

  • Session limits are enforced only for mobile and web session types
  • default sessions 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

  • undefined or null - 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'
  })
});
// 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():

  1. Skip validation for default session types
  2. Validate session type - must be mobile or web
  3. Retrieve settings - tenant-specific settings take precedence over global settings
  4. Check limits - compare active sessions count against configured limit
  5. 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:

  1. Logout from other devices - Free up session slots
  2. Use default session type - Not subject to limits
  3. Contact administrator - To adjust limits if needed

Multi-Tenant Behavior

Settings Priority

In multi-tenant mode, settings are resolved in this order:

  1. Tenant-specific settings - If tenant_Id matches the user's tenant
  2. Global settings - If no tenant-specific settings exist (tenant_Id: null)
  3. 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.js

Best 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

  1. "Session limit reached" but user has no active sessions

    • Check for expired sessions not yet cleaned up
    • Verify session cleanup job is running
  2. Limits not being enforced

    • Verify settings are properly configured
    • Check that authType is being passed in requests
  3. 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:

  1. Existing sessions continue to work (marked as default type)
  2. No immediate impact on current users
  3. Configure limits gradually - Start with high limits and reduce
  4. Update client applications to pass authType parameter

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

On this page