Refresh Token
Exchanges a refresh token for a new access token and refresh token. Use this to maintain user sessions without requiring re-login.
Endpointβ
POST /api/v1/auth/refresh
Authenticationβ
No authentication required, but requires valid refresh token.
Requestβ
Content-Typeβ
application/json
Request Bodyβ
| Field | Type | Required | Description |
|---|---|---|---|
refresh_token | string | Yes | Valid refresh token from login or previous refresh |
Example Requestβ
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Responseβ
Success Response (200 OK)β
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
New Tokens for Both
This endpoint returns both a new access token and a new refresh token. Always replace both tokens in your storage.
Response Fieldsβ
| Field | Type | Description |
|---|---|---|
access_token | string | New JWT access token (expires in 30 minutes) |
refresh_token | string | New JWT refresh token (expires in 7 days) |
token_type | string | Always "bearer" |
Token Rotationβ
This endpoint implements refresh token rotation for security:
- Each refresh generates a NEW refresh token
- Old refresh token is invalidated
- Always update your stored refresh token
Examplesβ
curl -X POST https://api.callcov.com/api/v1/auth/refresh \-H "Content-Type: application/json" \-d '{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}'Auto-Refresh Patternβ
Python Client with Auto-Refreshβ
import requests
from datetime import datetime, timedelta
import threading
class CallCovClient:
def __init__(self, access_token, refresh_token):
self.base_url = "https://api.callcov.com/api/v1"
self.access_token = access_token
self.refresh_token = refresh_token
self.token_expiry = datetime.now() + timedelta(minutes=30)
self.refresh_lock = threading.Lock()
def refresh_tokens(self):
"""Refresh access and refresh tokens"""
with self.refresh_lock:
response = requests.post(
f"{self.base_url}/auth/refresh",
json={"refresh_token": self.refresh_token}
)
if response.status_code == 200:
data = response.json()
self.access_token = data['access_token']
self.refresh_token = data['refresh_token']
self.token_expiry = datetime.now() + timedelta(minutes=30)
return True
return False
def get_headers(self):
"""Get authorization headers, refreshing token if needed"""
# Refresh if token expires in less than 5 minutes
if datetime.now() + timedelta(minutes=5) >= self.token_expiry:
if not self.refresh_tokens():
raise Exception("Failed to refresh token. Please log in again.")
return {"Authorization": f"Bearer {self.access_token}"}
def make_request(self, method, endpoint, **kwargs):
"""Make authenticated request with auto-refresh"""
headers = self.get_headers()
if 'headers' in kwargs:
kwargs['headers'].update(headers)
else:
kwargs['headers'] = headers
response = requests.request(
method,
f"{self.base_url}{endpoint}",
**kwargs
)
# If 401, try refreshing token once and retry
if response.status_code == 401:
if self.refresh_tokens():
headers = self.get_headers()
kwargs['headers'] = headers
response = requests.request(
method,
f"{self.base_url}{endpoint}",
**kwargs
)
return response
# Usage
client = CallCovClient(access_token, refresh_token)
# Automatically refreshes tokens when needed
response = client.make_request('GET', '/users/me')
print(response.json())
JavaScript/React with Auto-Refreshβ
class ApiClient {
constructor(accessToken, refreshToken) {
this.baseUrl = 'https://api.callcov.com/api/v1';
this.accessToken = accessToken;
this.refreshToken = refreshToken;
this.tokenExpiry = Date.now() + 30 * 60 * 1000; // 30 minutes
this.refreshPromise = null;
}
async refreshTokens() {
// Prevent multiple simultaneous refreshes
if (this.refreshPromise) {
return this.refreshPromise;
}
this.refreshPromise = fetch(`${this.baseUrl}/auth/refresh`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: this.refreshToken })
})
.then(async (response) => {
if (!response.ok) throw new Error('Refresh failed');
const data = await response.json();
this.accessToken = data.access_token;
this.refreshToken = data.refresh_token;
this.tokenExpiry = Date.now() + 30 * 60 * 1000;
// Update stored tokens
localStorage.setItem('access_token', data.access_token);
localStorage.setItem('refresh_token', data.refresh_token);
return true;
})
.catch(() => {
// Refresh failed - redirect to login
window.location.href = '/login';
return false;
})
.finally(() => {
this.refreshPromise = null;
});
return this.refreshPromise;
}
async getHeaders() {
// Refresh if token expires in less than 5 minutes
if (Date.now() + 5 * 60 * 1000 >= this.tokenExpiry) {
await this.refreshTokens();
}
return {
'Authorization': `Bearer ${this.accessToken}`
};
}
async request(method, endpoint, options = {}) {
const headers = await this.getHeaders();
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method,
headers: { ...headers, ...options.headers },
...options
});
// If 401, try refreshing once and retry
if (response.status === 401) {
const refreshed = await this.refreshTokens();
if (refreshed) {
const newHeaders = await this.getHeaders();
return fetch(`${this.baseUrl}${endpoint}`, {
method,
headers: { ...newHeaders, ...options.headers },
...options
});
}
}
return response;
}
}
// Usage
const client = new ApiClient(accessToken, refreshToken);
const response = await client.request('GET', '/users/me');
const userData = await response.json();
Errorsβ
401 Unauthorizedβ
Invalid refresh token:
{
"detail": "Invalid refresh token"
}
User not found or inactive:
{
"detail": "User not found or inactive"
}
When to Refreshβ
Refresh the access token when:
- Access token has expired (API returns 401)
- Access token will expire soon (preemptive refresh)
- Application starts up (check if token is expired)
Best Practicesβ
- Preemptive Refresh: Refresh 5 minutes before expiration
- Handle Failures: If refresh fails, redirect to login
- Update Storage: Always update both tokens
- Thread Safety: Use locks to prevent concurrent refresh attempts
- Retry Once: If API returns 401, try refreshing and retrying once
Security Considerationsβ
- Refresh token rotation: Each refresh invalidates the old refresh token
- Expiration: Refresh tokens expire in 7 days
- Secure storage: Store refresh tokens securely (httpOnly cookies recommended)
- No reuse: Old refresh tokens cannot be reused
Refresh Token Lifespanβ
| Event | Lifespan |
|---|---|
| Token created | 7 days |
| Token used for refresh | Immediately invalidated, new one issued |
| Token expired | Cannot be refreshed, user must log in |
Relatedβ
- Login - Get initial tokens
- User Profile - Use access token for API requests
- Getting Started: Authentication - Complete auth guide