Token Management

Proper token management ensures your integration remains secure and reliable. Follow these guidelines for handling access and refresh tokens.

Token Lifecycle

Authorization Code → Exchange → Access Token (1 hour) + Refresh Token (30 days)
                                      ↓
                              Token expires → Use Refresh Token → New Access Token
                                                    ↓
                                          Refresh Token expires → Re-authorize user

Storage Best Practices

Access Tokens

  • Store in memory or short-lived server-side cache
  • Never store in localStorage, cookies, or client-side code
  • Treat as a session credential — ephemeral by design

Refresh Tokens

  • Store encrypted in your database, associated with the user
  • Use server-side encryption (AES-256 or equivalent)
  • Never log refresh tokens in application logs
  • Index by user ID for easy lookup during token refresh

API Keys

  • Store in environment variables or a secrets manager (AWS Secrets Manager, HashiCorp Vault)
  • Never hardcode in source code
  • Never commit to version control (add to .gitignore)

Automatic Token Refresh

Implement automatic refresh in your API client to avoid disruption:

async function apiRequest(endpoint, options = {}) {
  let token = await getAccessToken();

  let response = await fetch(`https://api.otesse.com/v1${endpoint}`, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${token}`,
    },
  });

  // If token is expired, refresh and retry
  if (response.status === 401) {
    token = await refreshAccessToken();
    response = await fetch(`https://api.otesse.com/v1${endpoint}`, {
      ...options,
      headers: {
        ...options.headers,
        'Authorization': `Bearer ${token}`,
      },
    });
  }

  return response;
}

Token Revocation

Revoke tokens when:

  • A user disconnects your integration
  • You detect suspicious activity
  • A user's account is deactivated
curl -X POST https://auth.otesse.com/oauth/revoke \
  -H "Content-Type: application/json" \
  -d '{
    "token": "otesse_rt_def456...",
    "token_type_hint": "refresh_token",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'

Revoking a refresh token also invalidates all associated access tokens.

Error Handling

ErrorMeaningAction
invalid_tokenToken is expired or revokedRefresh the token or re-authorize
insufficient_scopeToken does not have the required scopeRequest additional scopes
invalid_grantAuthorization code or refresh token is invalidRe-authorize the user
rate_limitedToo many token requestsImplement exponential backoff

Monitoring

Track token usage through the API dashboard:

  • Active tokens per user and application
  • Token refresh frequency
  • Failed authentication attempts
  • Revoked tokens and reasons