dromara/Sa-Token · error · ApiKeyException

12302

12302

Error message

API Key 已过期: 

What it means

Thrown by SaApiKeyTemplate.checkApiKey(String) when the ApiKeyModel exists but ak.timeExpired() returns true — the key's expiresTime has passed. Code 12302 marks an expired key; the record is still present, only its validity window has elapsed.

Source

Thrown at sa-token-plugin/sa-token-apikey/src/main/java/cn/dev33/satoken/apikey/template/SaApiKeyTemplate.java:130

		if(apiKeyModel == null) {
			apiKeyModel = getApiKeyModelFromDatabase(apiKey);
			saveApiKey(apiKeyModel);
		}
		return apiKeyModel;
	}

	/**
	 * 校验 ApiKey,成功返回 ApiKeyModel,失败则抛出异常
	 * @param apiKey /
	 * @return /
	 */
	public ApiKeyModel checkApiKey(String apiKey) {
		ApiKeyModel ak = getApiKey(apiKey);
		if(ak == null) {
			throw new ApiKeyException("无效 API Key: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12301);
		}
		if(ak.timeExpired()) {
			throw new ApiKeyException("API Key 已过期: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12302);
		}
		if(! ak.getIsValid()) {
			throw new ApiKeyException("API Key 已被禁用: " + apiKey).setApiKey(apiKey).setCode(SaApiKeyErrorCode.CODE_12303);
		}
		return ak;
	}

	/**
	 * 持久化:ApiKeyModel
	 * @param ak /
	 */
	public void saveApiKey(ApiKeyModel ak) {
		if(ak == null) {
			return;
		}
		// 数据自检
		ak.checkByCanSaved();

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Issue a new key via createApiKey(...) and update the client with the new value
  2. For long-lived integrations, create the key with SaTokenDao.NEVER_EXPIRE or a multi-year window
  3. If expiry is intentional, rotate keys on a schedule before they lapse (monitor expiresIn())

Example fix

// before
// key created with 1-hour expiry yesterday
saApiKeyTemplate.checkApiKey(oldKey); // throws 12302

// after
String newKey = saApiKeyTemplate.createApiKey(10001, "order-service", SaTokenDao.NEVER_EXPIRE);
saApiKeyTemplate.checkApiKey(newKey);
Defensive patterns

Strategy: retry

Validate before calling

ApiKeyModel ak = saApiKeyTemplate.getApiKey(apiKey);
if (ak != null && ak.timeExpired()) {
    apiKey = reissueKey(ak.getLoginId()); // createApiKey(...)
}

Try / catch

catch (ApiKeyException e) { if (e.getCode() == SaApiKeyErrorCode.CODE_12302) { apiKey = reissue(); return retry(request); } throw e; }

Prevention

When it happens

Trigger: Calling checkApiKey / checkApiKeyScope / checkApiKeyScopeOr with a key whose expiresTime timestamp is in the past (only keys created with a finite expiry can trigger this).

Common situations: Short-lived keys expiring between requests; long-running batch jobs using a key created at startup; clock skew between app servers; admin set a short expiry without noticing; key created with expiresTime accidentally in the past.

Related errors


AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14). Data as JSON: /api/errors/b77434fe8f5f230d. Report an issue: GitHub.