MATIH Platform is in active MVP development. Documentation reflects current implementation status.
6. Identity & Access Management
Authentication
Refresh Tokens

Refresh Tokens

Production - POST /api/v1/auth/refresh

Refresh tokens enable long-lived sessions without requiring users to re-enter credentials. The IAM service implements refresh token rotation with token family tracking to detect and prevent token reuse attacks.


6.2.12Token Refresh Flow

Client                  AuthController          AuthenticationService
  |                           |                          |
  |--- POST /auth/refresh --->|                          |
  |   { refreshToken: "..." } |--- refreshToken() ----->|
  |                           |                          |--- Find valid token
  |                           |                          |--- Check user status
  |                           |                          |--- Generate new access token
  |                           |                          |--- Rotate refresh token
  |                           |                          |--- Save new token in family
  |<-- 200 (AuthResponse) ----|<-- AuthResponse ---------|

Request

curl -X POST http://localhost:8081/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "eyJhbGciOiJIUzI1NiJ9..."
  }'

Request Schema

FieldTypeRequiredDescription
refreshTokenStringYesThe refresh token to exchange

Response (200 OK)

{
  "accessToken": "eyJhbGciOiJIUzI1NiJ9...<new-access-token>",
  "refreshToken": "eyJhbGciOiJIUzI1NiJ9...<new-refresh-token>",
  "tokenType": "Bearer",
  "expiresIn": 900,
  "user": {
    "id": 1,
    "email": "jane.smith@example.com",
    "firstName": "Jane",
    "lastName": "Smith",
    "displayName": "Jane Smith",
    "tenantId": "00000000-0000-0000-0000-000000000001",
    "roles": ["ROLE_USER"],
    "emailVerified": true
  }
}

6.2.13Token Rotation

Every refresh token exchange produces a new refresh token and invalidates the old one. This is called refresh token rotation.

How Token Families Work

Each refresh token belongs to a token family identified by a UUID. When a user logs in, a new family is created. Each rotation creates a new token in the same family:

Login:     RefreshToken_A (family: F1, active)
Refresh 1: RefreshToken_A (family: F1, rotated) -> RefreshToken_B (family: F1, active)
Refresh 2: RefreshToken_B (family: F1, rotated) -> RefreshToken_C (family: F1, active)

Reuse Detection

If a previously rotated token is used again, it indicates a potential token theft:

RefreshToken refreshToken = refreshTokenRepository.findValidToken(token, Instant.now())
    .orElseThrow(() -> {
        // Check if token exists but is revoked (potential reuse attack)
        refreshTokenRepository.findByToken(token).ifPresent(t -> {
            if (t.isRevoked()) {
                log.warn("Refresh token reuse detected for family: {}", t.getTokenFamily());
                // Revoke ALL tokens in the family
                refreshTokenRepository.revokeAllByTokenFamily(
                    t.getTokenFamily(), Instant.now(), "Token reuse detected"
                );
            }
        });
        return new TokenException("Invalid or expired refresh token");
    });

When reuse is detected:

  1. All tokens in the family are revoked
  2. The user must re-authenticate with credentials
  3. The event is logged for security audit

User Status Checks

Before issuing new tokens, the service verifies the user account is still valid:

User user = refreshToken.getUser();
if (!user.isEnabled() || user.isAccountLocked()) {
    refreshToken.revoke("User account disabled or locked");
    refreshTokenRepository.save(refreshToken);
    throw new AuthenticationException("User account is not available");
}

6.2.14Token Expiration

Token TypeDefault ExpirationConfigurable
Access Token15 minutessecurity.jwt.access-token-expiration
Refresh Token7 dayssecurity.jwt.refresh-token-expiration

Error Codes

CodeHTTP StatusDescription
TOKEN_INVALID401Refresh token not found or already revoked
TOKEN_EXPIRED401Refresh token has expired
TOKEN_REUSE_DETECTED401Previously used token detected (all family tokens revoked)
AUTHENTICATION_FAILED401User account disabled or locked