Silent Token Refresh: Access vs Refresh Tokens with JWT Implementation
This article explains why silent token refresh is needed to prevent sudden logouts, demonstrates backend automatic token renewal using Java JWT (jjwt 0.9.1) with Maven dependencies, details the dual-token (AT/RT) frontend pattern for security and convenience, and discusses handling edge cases like long-idle form submissions that cause 401 errors.
Why Silent Token Refresh Is Needed
When a user performs actions on a system page, the session may suddenly expire and redirect to the login page. The root cause is token expiration leading to identity invalidation. The solution is automatic token renewal: either the backend generates a new token when the old one is about to expire and returns it in the response header, or a scheduled task extends the token's expiry time.
Backend Automatic Token Refresh
The backend checks the token's expiration time during validation. If the remaining time is below a threshold, it creates a new token from the existing token's claims and places it in the response header. The frontend intercepts the response, compares the new token with the stored one, and updates local storage if they differ.
Maven Dependencies
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.33</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>JwtUtil Class
The utility class uses HS256 signing with a configurable secret key (default "qx") and a default TTL of 24 hours (60*60*1000*24 ms). It provides overloaded createJWT methods accepting subject, optional TTL, and optional ID. The parseJWT method validates and returns claims. A helper generalKey decodes the Base64 secret into an AES SecretKeySpec.
public class JwtUtil {
public static final Long JWT_TTL = 60 * 60 * 1000 * 24;
public static final String JWT_KEY = "qx";
public static String getUUID() { ... }
public static String createJWT(String subject) { ... }
public static String createJWT(String subject, Long ttlMillis) { ... }
public static String createJWT(String id, String subject, Long ttlMillis) { ... }
private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) { ... }
public static SecretKey generalKey() { ... }
public static Claims parseJWT(String jwt) throws Exception { ... }
}Unit Test Verification
A test creates a token with subject "1735209949551763457", prints the token, extracts its expiration date, and calculates the difference between expiration (1703651262000 ms) and current time (1703564863035 ms) yielding 86,398,965 ms — close to the expected 86,400,000 ms for 24 hours. This confirms the token's expiry is correctly set.
Frontend Token Renewal with Dual Tokens (AT/RT)
The frontend-driven approach uses two tokens: an Access Token (AT) with a short expiry (e.g., 30 minutes) carried on every request, and a Refresh Token (RT) with a longer expiry (e.g., 7 days) used only against the auth service to obtain a new AT. This limits exposure of the AT, reducing hijack risk, while the RT's limited scope increases convenience. The author states this is a standard security practice akin to HTTPS over HTTP.
Edge Case: Long-Idle Form Submission
If a user spends a long time filling a form without sending requests, the token may expire. When the form is submitted, the backend returns 401. For the backend-only solution, the frontend should cache the form data locally, redirect to login, then restore the data after successful login. For the dual-token frontend solution, both AT and RT may have expired; the frontend must monitor RT expiry and proactively refresh it, or implement a draft-saving mechanism similar to the backend approach.
Further Reading
For more on stateless JWT usage, see the referenced link: https://t.zsxq.com/15xye5IWG.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
