What is the Refresh Token Grant Type?
The Refresh Token Grant Type is a mechanism that allows a client (application) to obtain a new access token using a refresh token without requiring the user to log in again.
Why is It Needed?
- Access tokens are short-lived (e.g., 5–15 minutes) for security reasons.
- Instead of forcing the user to log in again when the access token expires, we can use the refresh token to get a new access token.
- This allows for a smooth user experience and persistent sessions.
Components
| Term | Description |
|---|---|
| Authorization Server | The identity provider that issues tokens (e.g., Keycloak) |
| Client | The application (e.g., React app, Spring Boot app) |
| Access Token | Token used to access protected resources |
| Refresh Token | Token used to obtain a new access token after expiry |
| Resource Server | Backend APIs that require a valid access token |
How Does the Refresh Token Grant Type Work?
1. Initial Login
The user logs in using username/password (or via authorization code).
Keycloak returns:
{
"access_token": "eyJhbGciOi...",
"expires_in": 300,
"refresh_token": "eyJhbGciOi...",
"refresh_expires_in": 1800
}
access_tokenlasts for ~5 minutesrefresh_tokenlasts for ~30 minutes or longer
2. When Access Token Expires
The client sends a POST request to Keycloak to get a new access token using the refresh token.
Refresh Token Request Format
URL:
POST /realms/<realm-name>/protocol/openid-connect/token Host: http://localhost:8080
Headers:
Content-Type: application/x-www-form-urlencoded
Body:
grant_type=refresh_token client_id=myclient client_secret=client-secret (if confidential client) refresh_token=<refresh_token>
Refresh Token Example with curl
curl -X POST http://localhost:8080/realms/myrealm/protocol/openid-connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=refresh_token" \ -d "client_id=myclient" \ -d "client_secret=mysecret" \ -d "refresh_token=eyJhbGciOi..."
Server Response:
{
"access_token": "eyJhbGciOi...",
"expires_in": 300,
"refresh_token": "eyJhbGciOi... (new)",
"refresh_expires_in": 1800,
"token_type": "Bearer"
}
- The new
access_tokenis valid again. - Keycloak rotates the refresh token: you get a new one and should discard the old one.
Implementing Refresh Token Flow in Spring Boot
Spring Boot doesn’t automatically handle refresh tokens, but you can call the token endpoint manually like this:
public Map<String, Object> refreshAccessToken(String refreshToken) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "refresh_token");
body.add("client_id", "myclient");
body.add("client_secret", "<client-secret>");
body.add("refresh_token", refreshToken);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
ResponseEntity<Map> response = restTemplate.postForEntity(
"http://localhost:8080/realms/myrealm/protocol/openid-connect/token",
request,
Map.class
);
return response.getBody(); // contains new access and refresh tokens
}
React Apps (Using Keycloak JS Adapter)
When using keycloak-js:
keycloak.updateToken(30).then(refreshed => {
if (refreshed) {
console.log("Token refreshed successfully");
} else {
console.log("Token is still valid");
}
}).catch(() => {
console.error("Token refresh failed");
});
- The library automatically uses the refresh token to get a new access token when needed.
- This is the recommended way to use refresh tokens in browser-based apps.
Refresh Token Errors
| Error | Cause |
|---|---|
invalid_grant | Refresh token is invalid or expired |
unauthorized_client | Client is not allowed to use the grant type |
invalid_client | Wrong client credentials |
401 Unauthorized | Refresh token expired, user must re-authenticate |
Security Best Practices
- Never expose the refresh token to the browser (unless using a secure JS library like
keycloak-js). - Use HttpOnly cookies or keep it in backend memory.
- Rotate refresh tokens if supported (Keycloak does this).
- Set appropriate refresh token TTL in Keycloak for session control.
- Use HTTPS to prevent token interception.
