dromara/Sa-Token · error · SaSsoException

CODE_30005

CODE_30005

Error message

{result.getMsg()}

What it means

Thrown during ticket validation (SSO mode 2/3): the client sent a check-ticket message to the sso-server and the response's code was not 200. The exception carries the server's msg, so the actual failure reason (invalid ticket, bad sign, missing client config) is whatever the server replied.

Source

Thrown at sa-token-plugin/sa-token-sso/src/main/java/cn/dev33/satoken/sso/processor/SaSsoClientProcessor.java:357

			if(SaFoxUtil.isNotEmpty(cfg.getCurrSsoLogoutCall())) {
				ssoLogoutCall = cfg.getCurrSsoLogoutCall();
			}
			// 如果提供了当前 uri,则根据此值来计算:
			else if(SaFoxUtil.isNotEmpty(currUri)) {
				ssoLogoutCall = SaHolder.getRequest().getUrl().replace(currUri, apiName.ssoLogoutCall);
			}
			// 否则视为不注册单点注销回调地址
			else {
			}
		}

		// 发起请求
		SaSsoMessage message = ssoClientTemplate.buildCheckTicketMessage(ticket, ssoLogoutCall);
		SaResult result = ssoClientTemplate.pushMessageAsSaResult(message);

		// 如果 sso-server 响应的状态码非200,代表业务失败,将回应的 msg 字段作为异常抛出
		if(result.getCode() == null || result.getCode() != SaResult.CODE_SUCCESS) {
			throw new SaSsoException(result.getMsg()).setCode(SaSsoErrorCode.CODE_30005);
		}

		// 构建返回结果
		SaCheckTicketResult ctr = new SaCheckTicketResult();
		ctr.loginId = result.get(paramName.loginId);
		ctr.tokenValue = result.get(paramName.tokenValue, String.class);
		ctr.deviceId = result.get(paramName.deviceId, String.class);
		ctr.remainTokenTimeout = result.get(paramName.remainTokenTimeout, Long.class);
		ctr.remainSessionTimeout = result.get(paramName.remainSessionTimeout, Long.class);
		ctr.result = result;

		// 转换 loginId 和 centerId
		ctr.centerId = ctr.loginId;
		ctr.loginId = ssoClientTemplate.strategy.convertCenterIdToLoginId.run(ctr.centerId);

		return ctr;
	}

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Inspect the exact msg string — it mirrors the sso-server's error (invalid ticket vs sign error vs client not configured)
  2. Ensure the ticket is validated only once and immediately after redirect (tickets are one-time use in checkTicketParamAndDelete)
  3. Verify secret-key, server-url and client identifier match between the two sides
Defensive patterns

Strategy: try-catch

Try / catch

try {
    SaCheckTicketResult r = ssoClientTemplate.checkTicket(ticket);
} catch (SaSsoException e) {
    if(SaSsoErrorCode.CODE_30005 == e.getCode()) {
        // rethrow result.getMsg(); typically redirect back to /sso/auth to reissue ticket
    }
}

Prevention

When it happens

Trigger: Client callback /sso/login?ticket=... invokes ssoClientTemplate.checkTicket(ticket); the pushMessageAsSaResult call for buildCheckTicketMessage returns a SaResult whose code != 200 (or code is null because the response was not a valid SaResult at all).

Common situations: Ticket already consumed or expired on the server; secret-key mismatch causing sign verification failure on the server; server URL misconfigured so the client hit a 404 page; a gateway/filter intercepting the server-to-server call.

Related errors


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