Docs

Sessions API

Manage user sessions across all auth providers - list, validate, refresh, and revoke

Sessions API

Manage active user sessions across all authentication providers. Sessions are used to maintain authenticated state between requests.

Base Endpoint

/api/auth/sessions

List Active Sessions

Retrieve all active sessions for the current user.

Endpoint

GET /api/auth/sessions

Headers

Authorization: Bearer {session_token}
# OR session cookie is automatically sent

Success Response (200)

{
  "success": true,
  "data": {
    "sessions": [
      {
        "id": "sess_abc123",
        "userId": "usr_123456",
        "createdAt": "2024-01-15T10:30:00Z",
        "expiresAt": "2024-01-22T10:30:00Z",
        "lastActiveAt": "2024-01-15T14:45:00Z",
        "ipAddress": "192.168.1.1",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...",
        "device": {
          "type": "desktop",
          "browser": "Chrome",
          "os": "macOS"
        },
        "isCurrent": true
      },
      {
        "id": "sess_def456",
        "userId": "usr_123456",
        "createdAt": "2024-01-14T09:00:00Z",
        "expiresAt": "2024-01-21T09:00:00Z",
        "lastActiveAt": "2024-01-14T18:30:00Z",
        "ipAddress": "203.0.113.42",
        "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0...",
        "device": {
          "type": "mobile",
          "browser": "Safari",
          "os": "iOS"
        },
        "isCurrent": false
      }
    ],
    "total": 2
  }
}

Get Current Session

Validate and retrieve the current session details.

Endpoint

GET /api/auth/sessions/current

Success Response (200)

{
  "success": true,
  "data": {
    "session": {
      "id": "sess_abc123",
      "userId": "usr_123456",
      "expiresAt": "2024-01-22T10:30:00Z",
      "lastActiveAt": "2024-01-15T14:45:00Z"
    },
    "user": {
      "id": "usr_123456",
      "email": "user@example.com",
      "name": "John Doe",
      "organizations": [
        {
          "id": "org_789",
          "name": "Acme Inc",
          "role": "owner"
        }
      ]
    }
  }
}

Error Response (401)

{
  "success": false,
  "error": {
    "code": "SESSION_EXPIRED",
    "message": "Session has expired, please sign in again"
  }
}

Refresh Session

Extend an expiring session with a refresh token.

Endpoint

POST /api/auth/sessions/refresh

Request

{
  "refreshToken": "rt_xyz789..."
}

Success Response (200)

{
  "success": true,
  "data": {
    "session": {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "expiresAt": "2024-01-22T10:30:00Z",
      "refreshToken": "rt_newabc..."
    }
  }
}

Revoke Session

Sign out from a specific session.

Endpoint

DELETE /api/auth/sessions/:sessionId

Success Response (200)

{
  "success": true,
  "data": {
    "revoked": true
  },
  "message": "Session revoked successfully"
}

Revoke All Sessions

Sign out from all sessions except the current one.

Endpoint

DELETE /api/auth/sessions

Request Body (Optional)

{
  "keepCurrent": true // Default: true
}

Success Response (200)

{
  "success": true,
  "data": {
    "revokedCount": 3,
    "keptCurrent": true
  },
  "message": "3 sessions revoked successfully"
}

Code Examples

List Sessions

async function getSessions() {
  const response = await fetch('/api/auth/sessions', {
    credentials: 'include' // Include cookies
  });
  
  const result = await response.json();
  
  if (result.success) {
    return result.data.sessions;
  }
  
  throw new Error(result.error?.message);
}

React Hook for Session Management

import { useEffect, useState } from 'react';

interface Session {
  id: string;
  createdAt: string;
  expiresAt: string;
  lastActiveAt: string;
  device: {
    type: string;
    browser: string;
    os: string;
  };
  isCurrent: boolean;
}

export function useSessions() {
  const [sessions, setSessions] = useState<Session[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    fetchSessions();
  }, []);

  const fetchSessions = async () => {
    try {
      const response = await fetch('/api/auth/sessions', {
        credentials: 'include'
      });
      const result = await response.json();
      
      if (result.success) {
        setSessions(result.data.sessions);
      } else {
        setError(result.error?.message);
      }
    } catch {
      setError('Failed to fetch sessions');
    } finally {
      setIsLoading(false);
    }
  };

  const revokeSession = async (sessionId: string) => {
    const response = await fetch(`/api/auth/sessions/${sessionId}`, {
      method: 'DELETE',
      credentials: 'include'
    });
    
    const result = await response.json();
    
    if (result.success) {
      setSessions(sessions.filter(s => s.id !== sessionId));
    }
    
    return result;
  };

  const revokeAllSessions = async () => {
    const response = await fetch('/api/auth/sessions', {
      method: 'DELETE',
      credentials: 'include'
    });
    
    const result = await response.json();
    
    if (result.success) {
      // Keep only current session
      setSessions(sessions.filter(s => s.isCurrent));
    }
    
    return result;
  };

  return {
    sessions,
    isLoading,
    error,
    revokeSession,
    revokeAllSessions,
    refresh: fetchSessions
  };
}

Session Security Component

export function SessionManager() {
  const { sessions, isLoading, revokeSession, revokeAllSessions } = useSessions();

  if (isLoading) return <div>Loading sessions...</div>;

  return (
    <div className="session-manager">
      <h2>Active Sessions</h2>
      
      <div className="sessions-list">
        {sessions.map(session => (
          <div 
            key={session.id} 
            className={`session-card ${session.isCurrent ? 'current' : ''}`}
          >
            <div className="device-info">
              <span className="device-type">{session.device.type}</span>
              <span className="browser">{session.device.browser}</span>
              <span className="os">{session.device.os}</span>
              {session.isCurrent && <span className="badge">Current</span>}
            </div>
            
            <div className="session-meta">
              <p>Last active: {new Date(session.lastActiveAt).toLocaleString()}</p>
              <p>Expires: {new Date(session.expiresAt).toLocaleString()}</p>
            </div>
            
            {!session.isCurrent && (
              <button 
                onClick={() => revokeSession(session.id)}
                className="revoke-btn"
              >
                Sign Out
              </button>
            )}
          </div>
        ))}
      </div>
      
      {sessions.length > 1 && (
        <button 
          onClick={revokeAllSessions}
          className="revoke-all-btn"
        >
          Sign Out All Other Devices
        </button>
      )}
    </div>
  );
}

Provider-Specific Behavior

BetterAuth

  • Sessions stored in database with configurable expiry
  • Supports concurrent session limits per user
  • Device fingerprinting for security

NextAuth

  • JWT sessions: Stateless, encoded in token
  • Database sessions: Stored in session table
  • Automatic session rotation on refresh

Clerk

  • Sessions managed by Clerk infrastructure
  • Automatic session refresh
  • Device tracking included

AuthKit

  • WorkOS session management
  • Organization-aware sessions
  • SSO session synchronization

Session Security

FeatureImplementation
ExpirationConfigurable TTL (default: 7 days)
RotationRefresh tokens rotate on use
Concurrent LimitsMax 10 active sessions per user
IP BindingOptional IP validation
Device FingerprintBrowser + OS detection

Webhook Events

EventDescription
session.createdNew session established
session.refreshedSession token rotated
session.revokedSession manually ended
session.expiredSession TTL reached

Rate Limits

  • List sessions: 60 requests per minute
  • Refresh session: 10 requests per minute
  • Revoke session: 30 requests per minute

On this page