Answer
Token Refresh and Session Management in API Test Automation
Managing authentication tokens efficiently is critical for reliable API test suites.
Strategy 1: Fetch Once Per Suite
Java
public class BaseApiTest {
private static String ACCESS_TOKEN;
private static long TOKEN_EXPIRY;
@BeforeSuite
public void setUp() {
ACCESS_TOKEN = fetchToken();
TOKEN_EXPIRY = System.currentTimeMillis() + (3600 * 1000); // 1 hour
}
private String fetchToken() {
Response response = given()
.contentType(ContentType.JSON)
.body("{ \"username\": \"testuser\", \"password\": \"testpass\" }")
.when()
.post(BASE_URL + "/auth/login");
assertEquals(response.getStatusCode(), 200);
return response.jsonPath().getString("access_token");
}
protected String getToken() {
// Refresh token if expired
if (System.currentTimeMillis() >= TOKEN_EXPIRY) {
ACCESS_TOKEN = fetchToken();
TOKEN_EXPIRY = System.currentTimeMillis() + (3600 * 1000);
}
return ACCESS_TOKEN;
}
}
Strategy 2: Token Refresh using Refresh Token
Java
public class TokenManager {
private static String accessToken;
private static String refreshToken;
private static long expiresAt;
public static void login() {
Response response = given()
.body("{ \"username\": \"user\", \"password\": \"pass\" }")
.contentType(ContentType.JSON)
.when()
.post("/auth/login");
accessToken = response.jsonPath().getString("access_token");
refreshToken = response.jsonPath().getString("refresh_token");
int expiresIn = response.jsonPath().getInt("expires_in");
expiresAt = System.currentTimeMillis() + (expiresIn * 1000L);
}
public static String getAccessToken() {
if (System.currentTimeMillis() >= expiresAt - 30000) { // refresh 30s early
refreshAccessToken();
}
return accessToken;
}
private static void refreshAccessToken() {
Response response = given()
.body("{ \"refresh_token\": \"" + refreshToken + "\" }")
.contentType(ContentType.JSON)
.when()
.post("/auth/refresh");
if (response.getStatusCode() == 200) {
accessToken = response.jsonPath().getString("access_token");
int expiresIn = response.jsonPath().getInt("expires_in");
expiresAt = System.currentTimeMillis() + (expiresIn * 1000L);
} else {
// Refresh token also expired — re-login
login();
}
}
}
Strategy 3: Per-Test Token with @BeforeMethod
Java
public class UserApiTest {
private String token;
@BeforeMethod
public void setUp() {
// Fetch fresh token before each test (slower but safest)
token = AuthApi.getToken();
}
@Test
public void testGetUser() {
given()
.header("Authorization", "Bearer " + token)
.when()
.get("/api/users/1")
.then()
.statusCode(200);
}
}
Handling 401 — Auto-Retry with New Token
Java
public Response executeWithRetry(Supplier<Response> request) {
Response response = request.get();
if (response.getStatusCode() == 401) {
// Token expired — refresh and retry once
TOKEN = TokenManager.refreshAccessToken();
response = request.get();
}
return response;
}
Best Practices
| Practice | Reason |
|---|---|
| Fetch token once per suite | Performance — avoid login on every test |
| Implement refresh logic | Handle long-running test suites |
| Store token in ThreadLocal | Thread-safe for parallel tests |
| Never hardcode tokens | Security — use env variables or fetch dynamically |
| Log token expiry issues | Easier debugging |
