Skip to main content
POST
/
auth
/
refresh
curl -X POST "https://api.chronos.app/auth/refresh" \
  -H "Accept: application/json" \
  -b "__Host-refresh=eyJhbG..."
{
  "user": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "[email protected]",
    "name": "Jane Doe",
    "avatar_url": "https://lh3.googleusercontent.com/a/...",
    "created_at": "2026-03-04T10:30:00.000Z"
  },
  "expires_at": 1709556600
}

Request

Cookies

This endpoint requires the refresh token cookie set during authentication. No request body is needed.

Response

user
object
required
The authenticated user’s current profile information
expires_at
integer
required
Unix timestamp (in seconds) when the new session expires
curl -X POST "https://api.chronos.app/auth/refresh" \
  -H "Accept: application/json" \
  -b "__Host-refresh=eyJhbG..."
{
  "user": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "[email protected]",
    "name": "Jane Doe",
    "avatar_url": "https://lh3.googleusercontent.com/a/...",
    "created_at": "2026-03-04T10:30:00.000Z"
  },
  "expires_at": 1709556600
}

Cookies Updated

This endpoint updates the session cookies with new values:
session_token
cookie
Updated session cookie with new access token
  • HttpOnly: Yes
  • Secure: Yes (production)
  • SameSite: Lax or Strict (production)
refresh_token
cookie
Updated refresh token cookie (if token rotation occurred)
  • HttpOnly: Yes
  • Secure: Yes (production)
  • SameSite: Lax or Strict (production)
csrf_token
cookie
Fresh CSRF token for the new session

Error Codes

401
error
Unauthorized - One of the following occurred:
  • No refresh token cookie present
  • Refresh token has been revoked
  • Refresh token is invalid or expired
  • Failed to retrieve user data
429
error
Rate Limit Exceeded - Too many refresh requests from this IP address

Rate Limits

This endpoint is rate-limited according to the RATE_LIMIT_AUTH configuration. The rate limiter uses the client’s IP address as the key.

Implementation Details

Refresh Flow

  1. Token Validation: Checks if refresh token exists in request cookies
  2. Revocation Check: Verifies the refresh token hasn’t been revoked in the database
  3. Session Refresh: Calls Supabase Auth to refresh the session
  4. Token Rotation: If Supabase returns a new refresh token:
    • Revokes the old refresh token in the database
    • Updates cookies with new refresh token
  5. Cookie Update: Sets new session cookies (access token, refresh token, CSRF token)
  6. User Data: Fetches and returns current user profile

Token Rotation

Supabase may rotate refresh tokens based on its security policies. When rotation occurs:
  • The old refresh token is immediately revoked with expiration set to current time
  • The new refresh token is stored in cookies
  • Token revocation is tracked in the revoked_tokens table

Revocation Tracking

Revoked tokens are stored with:
  • Token hash (for lookup)
  • Token type (refresh)
  • User ID
  • Expiration timestamp
  • Revocation reason
This prevents reuse of old refresh tokens even if intercepted.

Security Notes

  • Refresh tokens are stored as HTTP-only cookies, preventing JavaScript access
  • Token revocation ensures old refresh tokens cannot be reused
  • Each refresh generates a fresh CSRF token
  • Failed refresh attempts do not reveal whether the token was invalid or revoked
  • All token operations are logged for security auditing

Usage Pattern

// Check if session is expiring soon (e.g., within 5 minutes)
function shouldRefreshSession(expiresAt) {
  const now = Math.floor(Date.now() / 1000);
  const fiveMinutes = 5 * 60;
  return expiresAt - now < fiveMinutes;
}

// Refresh session before it expires
async function ensureValidSession(expiresAt) {
  if (shouldRefreshSession(expiresAt)) {
    const response = await fetch('/auth/refresh', {
      method: 'POST',
      credentials: 'include'
    });
    
    if (response.ok) {
      const data = await response.json();
      return data.expires_at;
    }
  }
  return expiresAt;
}
Best Practice: Implement automatic session refresh in your application by checking expires_at before making API requests. Refresh the session proactively when it’s within 5 minutes of expiring to ensure uninterrupted access.
Source: backend/app/routers/auth.py:220-263

Build docs developers (and LLMs) love