Sessions

Session management, logout, and token refresh endpoints

Updated Apr 12, 2026 Edit this page

Session Management

Endpoints for managing user sessions, logging out, and refreshing access tokens.


Endpoints

Method Path Description
POST /api/auth/logout Logout and revoke session
POST /api/auth/refresh Refresh access token
POST /auth/revoke Revoke a token (RFC 7009)

POST /api/auth/logout

Logout the current user and revoke their session.

Synopsis

Property Value
Authentication Required (JWT)
Authorization Authenticated User
Rate Limit 1 request/second (Burst: 20)
Idempotent Yes

Request Headers

Header Value Required
Authorization Bearer {jwt} Yes

Example Request

curl -X POST https://sso.example.com/api/auth/logout \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Response (200 OK)

{
  "message": "Logged out successfully"
}

Behavior

  • Current session is marked as revoked
  • Associated refresh token is invalidated
  • JWT remains valid until expiration (stateless)
  • To enforce immediate logout, services should check jti against session store

POST /api/auth/refresh

Exchange a valid refresh token for a new access token.

Synopsis

Property Value
Authentication None (uses refresh token)
Rate Limit 1 request/second (Burst: 20)
Idempotent No (token rotation)

Request Body

Field Type Required Description
refresh_token string Yes Valid refresh token (UUID)

Example Request

curl -X POST https://sso.example.com/api/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "550e8400-e29b-41d4-a716-446655440000"
  }'

Response (200 OK)

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "refresh_token": "660f9500-e30c-41d5-b827-557766551111",
  "expires_in": 86400
}

Response Fields

Field Type Description
access_token string New JWT access token
refresh_token string New refresh token (rotated)
token_type string Always "Bearer"
expires_in integer Token lifetime in seconds

Errors

Status Code Condition
401 UNAUTHORIZED Invalid or expired refresh token
401 SESSION_REVOKED Session has been revoked

Security Notes

  • Refresh tokens are rotated on each use
  • Old token becomes invalid after rotation
  • Storing old token and attempting use will fail

POST /auth/revoke

Revoke an access token or refresh token according to RFC 7009.

Synopsis

Property Value
Authentication Public
Rate Limit 1 request/second (Burst: 20)

Request Body (Form Data)

Field Type Required Description
token string Yes Token to revoke
token_type_hint string No access_token or refresh_token

Example Request

curl -X POST https://sso.example.com/auth/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=550e8400-e29b-41d4-a716-446655440000&token_type_hint=refresh_token"

Response (200 OK): Empty response (always returns 200 for security).


Session Invalidation Events

Sessions are automatically invalidated when:

Event Scope Description
Password Change All other sessions Current session preserved
MFA Disable All sessions Full re-authentication required
Admin Force-Logout Specific user All sessions for user
Account Suspension All sessions Organization suspended

Token Lifetimes

Token Type Lifetime Configurable
Access Token 24 hours No
Refresh Token 30 days No
Pre-auth Token 10 minutes No

Implementing Token Refresh

Automatic Refresh Pattern

class AuthClient {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
    this.accessToken = null;
    this.refreshToken = null;
  }

  async fetch(url, options = {}) {
    options.headers = {
      ...options.headers,
      'Authorization': `Bearer ${this.accessToken}`
    };

    let response = await fetch(this.baseUrl + url, options);

    if (response.status === 401) {
      const error = await response.json();
      
      if (error.error_code === 'TOKEN_EXPIRED') {
        await this.refreshTokens();
        
        // Retry with new token
        options.headers['Authorization'] = `Bearer ${this.accessToken}`;
        response = await fetch(this.baseUrl + url, options);
      }
    }

    return response;
  }

  async refreshTokens() {
    const response = await fetch(this.baseUrl + '/api/auth/refresh', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refresh_token: this.refreshToken })
    });

    if (!response.ok) {
      // Refresh failed, user must re-authenticate
      throw new Error('Session expired');
    }

    const data = await response.json();
    this.accessToken = data.access_token;
    this.refreshToken = data.refresh_token;
  }

  logout() {
    return fetch(this.baseUrl + '/api/auth/logout', {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${this.accessToken}` }
    });
  }
}

Session Storage Recommendations

Environment Access Token Refresh Token
Browser SPA Memory only httpOnly cookie
Mobile App Secure storage Secure storage
Server-side Environment/secrets manager Environment/secrets manager

Security Best Practices:

  1. Never store access tokens in localStorage
  2. Use httpOnly cookies for refresh tokens when possible
  3. Implement token rotation
  4. Clear tokens on logout
  5. Handle refresh failures gracefully