How to Configure JWT Token Refresh and Expiration in Sa-Token: A Complete Guide to ContiNew-Admin

Configure JWT token refresh and expiration in Sa-Token by enabling JWT-simple mode in application.yml, setting dynamic-active-timeout: true for automatic refresh, and defining per-client timeout (absolute expiry) and activeTimeout (idle expiry) values that are applied via SaLoginParameter during authentication.

ContiNew-Admin leverages Sa-Token with JWT-simple mode to provide flexible, client-specific token lifecycle management. Understanding how to configure JWT token refresh and expiration in Sa-Token requires navigating three distinct configuration layers—from global YAML settings to dynamic client-specific parameters. This guide breaks down the exact implementation found in the continew-org/continew-admin repository, showing you how to control token longevity and automatic renewal based on the actual source code.

Understanding the Three Configuration Layers

The ContiNew-Admin project implements a hierarchical approach to token management. Each layer overrides the previous one, allowing for both global defaults and client-specific customization:

  • Global Sa-Token configuration defines the JWT mode, secret keys, and dynamic timeout behavior in application.yml
  • Client-side configuration stores per-client timeout and activeTimeout values in the database via the Client entity
  • Login-time parameters bind these values to individual tokens through SaLoginParameter during the authentication handshake

Global Sa-Token Configuration

All global JWT settings reside in continew-server/src/main/resources/config/application.yml. This file controls the fundamental token behavior for the entire application.


# --- ### Sa-Token 配置

sa-token:
  # Token 名称(同时也是 cookie 名称)

  token-name: Authorization
  # 是否启用动态 activeTimeout 功能

  dynamic-active-timeout: true
  # JWT 秘钥(用于签名和校验 JWT)

  jwt-secret-key: asdasdasifhueuiwyurfewbfjsdafjk
  extension:
    enabled: true
    enableJwt: true        # <‑‑ 开启 JWT‑simple 模式

    dao.type: REDIS        # 持久化方式

The critical settings for JWT token refresh and expiration in this configuration are:

  • enableJwt: true activates JWT-simple mode, causing Sa-Token to generate signed JWT tokens rather than opaque references
  • dynamic-active-timeout: true enables the idle timeout mechanism that automatically refreshes the token's last-active timestamp on each validated request
  • jwt-secret-key provides the HMAC secret used to sign and verify token integrity

You may optionally uncomment the global timeout and active-timeout fields in this file to establish site-wide defaults (for example, timeout: 86400 for a 24-hour absolute expiration).

Per-Client Token Lifetime Configuration

ContiNew-Admin allows individual clients (web applications, mobile apps, or API consumers) to specify their own token expiration policies. These values are defined in the client model and stored persistently.

The relevant fields appear in three files:

// ClientResp.java fragment
private Long timeout;        // token 有效期(秒),-1 表示永不过期
private Long activeTimeout;  // token 空闲失效时间(秒),-1 表示不限制
  • timeout: Represents the absolute token expiration time in seconds. A value of -1 indicates the token never expires absolutely.
  • activeTimeout: Represents the idle timeout in seconds. If the token remains unused for this duration, it expires. A value of -1 disables idle expiration.

When creating or updating a client through the admin interface, these values populate the ClientDO entity and subsequently drive token generation for that specific client's authentication sessions.

Applying Token Settings During Authentication

When a user authenticates, the system binds the client-specific timeout values to the token through SaLoginParameter. This occurs in continew-system/src/main/java/top/continew/admin/auth/AbstractLoginHandler.java.

// AbstractLoginHandler.authenticate(..) – relevant fragment
SaLoginParameter loginParameter = new SaLoginParameter();
loginParameter.setActiveTimeout(client.getActiveTimeout()); // idle expiration
loginParameter.setTimeout(client.getTimeout());             // absolute expiration
...
StpUtil.login(userContext.getId(),
               loginParameter.setExtraData(BeanUtil.beanToMap(new UserExtraContext(ServletUtils.getRequest()))));

The StpUtil.login() method receives these parameters and embeds the expiration claims within the JWT payload. Because these values originate from the specific client record associated with the login request, different clients can simultaneously maintain different token lifecycle policies under the same authentication endpoint.

Automatic Token Refresh Mechanism

Token refresh operates transparently when dynamic-active-timeout is enabled. The mechanism relies on Sa-Token's interceptor chain configured in continew-server/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java.

@Bean
public SaInterceptor saInterceptor() {
    return new SaExtensionInterceptor(handle -> SaRouter.match(StringConstants.PATH_PATTERN)
        .notMatch(properties.getSecurity().getExcludes())
        .check(r -> {
            // normal sign‑validation or login check
            StpUtil.checkLogin();
            // … additional checks …
        }));
}

When StpUtil.checkLogin() executes during request processing, Sa-Token performs two operations:

  1. Validates the current token against both the absolute timeout and the idle activeTimeout
  2. If validation succeeds, automatically updates the token's last-active timestamp, effectively resetting the idle timeout window

This means as long as the client sends requests within the activeTimeout interval (e.g., every 30 minutes if activeTimeout is 1800 seconds), the token remains valid indefinitely regardless of the absolute timeout setting. No explicit refresh endpoint or manual token exchange is required.

Implementation Walkthrough

To implement JWT token refresh and expiration in your ContiNew-Admin instance:

  1. Configure the JWT foundation in application.yml:

    • Set sa-token.extension.enableJwt: true
    • Define sa-token.jwt-secret-key with a cryptographically secure random string
    • Enable sa-token.dynamic-active-timeout: true
  2. Define global fallbacks (optional):

    • Uncomment and set sa-token.timeout for default absolute expiration
    • Uncomment and set sa-token.active-timeout for default idle expiration
  3. Create a client configuration via the admin API or database:

    • Set timeout to 86400 for 24-hour absolute expiry, or -1 for no expiry
    • Set activeTimeout to 1800 for 30-minute idle timeout, or -1 to disable
  4. Authenticate using the client credentials:

    • The system automatically retrieves the client's timeout settings
    • AbstractLoginHandler applies these to SaLoginParameter
    • Sa-Token generates a JWT containing the expiration claims
  5. Verify automatic refresh:

    • Make subsequent requests within the activeTimeout window
    • Observe that StpUtil.checkLogin() extends the token life without requiring a new login

Summary

Configuring JWT token refresh and expiration in Sa-Token within ContiNew-Admin involves coordinating global YAML settings with per-client database records:

  • Enable JWT-simple mode and dynamic-active-timeout in application.yml to activate the refresh infrastructure
  • Store client-specific timeout (absolute) and activeTimeout (idle) values in the ClientDO entity
  • Apply these values via SaLoginParameter in AbstractLoginHandler.authenticate() during login
  • Rely on SaInterceptor and StpUtil.checkLogin() to automatically refresh the idle timeout on every valid request
  • Use -1 for either timeout value to disable that specific expiration mechanism

Frequently Asked Questions

What is the difference between timeout and activeTimeout in Sa-Token?

Timeout represents the absolute expiration time—the maximum lifetime of a token regardless of activity, measured in seconds since creation. ActiveTimeout represents the idle expiration time—the duration of inactivity allowed before the token becomes invalid. When dynamic-active-timeout is enabled, each request resets the activeTimeout counter, while the timeout counter continues toward its absolute limit. Set either value to -1 to disable that specific expiration check.

How does automatic token refresh work without a dedicated refresh endpoint?

Sa-Token's dynamic-active-timeout mechanism eliminates the need for explicit refresh endpoints. When configured in SaTokenConfiguration, the SaInterceptor calls StpUtil.checkLogin() on every protected request. This method automatically updates the token's last-active timestamp in Redis if the token is valid, effectively extending the idle window defined by activeTimeout. The token remains valid as long as the user remains active within the specified interval.

Can I use standard Sa-Token tokens instead of JWT in ContiNew-Admin?

Yes. To disable JWT mode and revert to Sa-Token's default UUID-based token mechanism, set sa-token.extension.enableJwt: false in application.yml. This change forces Sa-Token to generate opaque token strings rather than signed JWTs. Note that this requires different handling for token persistence and validation, though the timeout and activeTimeout mechanisms continue to function identically through the Redis-backed DAO configuration.

Where does ContiNew-Admin store JWT token state when using Redis?

According to the configuration in application.yml, setting sa-token.extension.dao.type: REDIS directs Sa-Token to persist token metadata—including timeout timestamps, active timeout tracking, and session mapping—to Redis. While the JWT itself contains signed claims readable by clients, the server-side state required for timeout enforcement and concurrent login management resides in Redis key-value entries managed by Sa-Token's DAO layer.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →