Exchange a valid refresh token for a new access token and a new refresh token. Public access without authentication. Old refresh token is immediately invalidated (token rotation).
- Axios interceptor on the frontend calls this endpoint automatically when an API request returns 401 Unauthorized.
- Token rotation: every successful refresh invalidates the old refresh token and issues a new one.
- If the refresh token is expired or not found, the user must log in again.
- Access token expires after 15 minutes; new refresh token expires after 14 days.
sequenceDiagram
actor User
FE->>FE: API call returns 401 Unauthorized
FE->>FE: Axios interceptor intercepts response
FE->>+BE: POST /api/v1/auth/refresh <br> RefreshTokenRequest
BE->>BE: validate request
alt request is invalid
BE-->>FE: 400 Bad Request <br> ErrorResponse
end
BE->>DB: find refresh token record
alt token not found
BE-->>FE: 401 Unauthorized <br> ErrorResponse
end
BE->>BE: check token expiry
alt token is expired
BE-->>FE: 401 Unauthorized <br> ErrorResponse
end
BE->>DB: invalidate old refresh token
BE->>BE: generate new access token
BE->>BE: generate new refresh token
BE->>DB: store new refresh token
BE->>-FE: 200 OK <br> AuthResponse
FE->>FE: store new tokens in localStorage
FE->>FE: retry original request with new access token
FE-->>User: original request result displayed
POST /api/v1/auth/refresh RefreshTokenRequest:
{
"refreshToken": "*****"
}
200 OK AuthResponse:
{
"data": {
"accessToken": "*****",
"refreshToken": "*****"
}
}
400 Bad Request (validation) ErrorResponse:
{
"status": 400,
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"errors": [
{ "field": "refreshToken", "message": "must not be blank" }
]
}
401 Unauthorized (token invalid or expired) ErrorResponse:
{
"status": 401,
"code": "AUTHENTICATION_FAILED",
"message": "Refresh token is invalid or expired"
}
Frontend
Validations
| Field | Constraints | Size | Pattern | Note |
|---|---|---|---|---|
| refreshToken | not_blank | read from localStorage by Axios interceptor |
Backend
Validations
| Field | Constraints | Size | Pattern | Note |
|---|---|---|---|---|
| refreshToken | not_blank |
Test Cases
| GIVEN | WHEN | THEN |
|---|---|---|
| valid, non-expired refresh token | refresh is called | 200 OK with new access token and new refresh token returned |
| valid refresh token used | refresh is called | old refresh token is invalidated in DB |
| refresh token not found in DB | refresh is called | 401 AUTHENTICATION_FAILED error response is returned |
| refresh token is expired | refresh is called | 401 AUTHENTICATION_FAILED error response is returned |
| refreshToken field is blank | refresh is called | 400 VALIDATION_ERROR error response is returned |
| invalid request (empty body) | refresh is called | 400 VALIDATION_ERROR error response is returned |
Was this page helpful?
Thanks for the feedback.