Pular para o conteúdo principal

POST /api/token/refresh

Obtem um novo token de acesso utilizando o refresh token.

Endpoint

POST /api/token/refresh

Headers

HeaderValorObrigatorio
Content-Typeapplication/jsonSim

Corpo da requisicao

{
"refresh_token": "string"
}
CampoTipoObrigatorioDescricao
refresh_tokenstringSimToken de atualizacao obtido no login

Resposta de sucesso

Codigo: 200 OK

{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3MDUzMTU5NDUsImV4cCI6MTcwNTMxOTU0NSwicm9sZXMiOlsiUk9MRV9BRE1JTiJdLCJlbWFpbCI6ImFkbWluQHBjaC1zaWcuc24ifQ...",
"refresh_token": "e2f3a4b5c6d7e8f9g0h1i2j3k4l5m6n7o8p9q0r1"
}
CampoTipoDescricao
tokenstringNovo token JWT de acesso
refresh_tokenstringNovo refresh token (rotacao)

Respostas de erro

401 Unauthorized - Refresh token invalido

{
"code": 401,
"message": "Invalid refresh token"
}

401 Unauthorized - Refresh token expirado

{
"code": 401,
"message": "Refresh token has expired"
}

Exemplos

cURL

curl -X POST https://sig.ucp-pch.org/api/token/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "d1f2a3b4c5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0"
}'

JavaScript

const refreshAccessToken = async () => {
const refreshToken = localStorage.getItem('refresh_token');

if (!refreshToken) {
throw new Error('No refresh token available');
}

const response = await fetch('https://sig.ucp-pch.org/api/token/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
refresh_token: refreshToken
})
});

if (!response.ok) {
// Refresh token invalido, redirecionar para login
localStorage.removeItem('token');
localStorage.removeItem('refresh_token');
window.location.href = '/login';
throw new Error('Session expired');
}

const data = await response.json();

// Atualizar os tokens
localStorage.setItem('token', data.token);
localStorage.setItem('refresh_token', data.refresh_token);

return data.token;
};

JavaScript - Interceptor Axios

import axios from 'axios';

const api = axios.create({
baseURL: 'https://sig.ucp-pch.org/api'
});

// Interceptor para atualizar automaticamente o token
api.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;

if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;

try {
const newToken = await refreshAccessToken();
originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
return api(originalRequest);
} catch (refreshError) {
return Promise.reject(refreshError);
}
}

return Promise.reject(error);
}
);

Python

import requests

def refresh_token(current_refresh_token):
response = requests.post(
'https://sig.ucp-pch.org/api/token/refresh',
json={
'refresh_token': current_refresh_token
}
)

if response.status_code == 200:
data = response.json()
return {
'token': data['token'],
'refresh_token': data['refresh_token']
}
else:
raise Exception('Failed to refresh token')

# Utilizacao
try:
tokens = refresh_token('d1f2a3b4c5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0')
print(f"Novo token: {tokens['token'][:50]}...")
except Exception as e:
print(f"Erro: {e}")

Rotacao dos tokens

O sistema utiliza a rotacao dos refresh tokens:

  1. Cada chamada a /api/token/refresh gera um novo refresh token
  2. O antigo refresh token e invalidado
  3. Isto limita o risco em caso de roubo do refresh token
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ Cliente │ │ Backend │ │ Redis │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ refresh_token_A │ │
│──────────────────▶│ │
│ │ Verificar token_A │
│ │──────────────────▶│
│ │ OK │
│ │◀──────────────────│
│ │ Invalidar token_A │
│ │──────────────────▶│
│ │ Criar token_B │
│ │──────────────────▶│
│ token + token_B │ │
│◀──────────────────│ │

Boas praticas

Quando atualizar?

  • Proativamente: Alguns minutos antes da expiracao do token
  • Reativamente: Apos receber um erro 401

Calculo do momento de atualizacao

const shouldRefreshToken = () => {
const token = localStorage.getItem('token');
if (!token) return false;

try {
const payload = JSON.parse(atob(token.split('.')[1]));
const expiresAt = payload.exp * 1000;
const now = Date.now();

// Atualizar 5 minutos antes da expiracao
return expiresAt - now < 5 * 60 * 1000;
} catch {
return false;
}
};

Notas

  • O refresh token expira apos 7 dias
  • Armazene o refresh token de forma segura (httpOnly cookie se possivel)
  • Em caso de erro de atualizacao, redirecione o utilizador para a pagina de login