dromara/Sa-Token · error · SaOAuth2ClientModelException

30113

30113

Error message

无效 redirect_url:

What it means

Thrown by SaOAuth2Template.checkRedirectUri when the redirect_uri passed to the OAuth2 authorize endpoint is not a syntactically valid URL (SaFoxUtil.isUrl fails). The library validates the callback URL before issuing an authorization code, because the redirect_uri is where the code gets delivered; an unparseable value cannot be trusted or matched. Error code is 30113 and the offending URL is appended to the message.

Source

Thrown at sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/template/SaOAuth2Template.java:153

						.setClientId(cm.clientId)
						.setScope(scope)
						.setCode(SaOAuth2ErrorCode.CODE_30112);
			}
		}
		return cm;
	}

	// --------- redirect_uri 相关

	/**
	 * 校验:该 Client 使用指定 url 作为回调地址,是否合法
	 * @param clientId 应用id
	 * @param url 指定url
	 */
	public void checkRedirectUri(String clientId, String url) {
		// 1、是否是一个有效的url
		if( ! SaFoxUtil.isUrl(url)) {
			throw new SaOAuth2ClientModelException("无效 redirect_url:" + url)
					.setClientId(clientId)
					.setCode(SaOAuth2ErrorCode.CODE_30113);
		}

		// 2、截取掉?后面的部分
		int qIndex = url.indexOf("?");
		if(qIndex != -1) {
			url = url.substring(0, qIndex);
		}

		// 3、不允许出现@字符
		if(url.contains("@")) {
			//  为什么不允许出现 @ 字符呢,因为这有可能导致 redirect_url 参数绕过 AllowUrl 列表的校验
			//
			//  举个例子 SaClientModel 配置:
			//       allow-url=http://sa-oauth-client.com*
			//
			//  开发者原意是为了允许 sa-oauth-client.com 下的所有地址都可以下放 code

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Ensure redirect_uri is an absolute URL with scheme and host, e.g. http://client.example.com/callback
  2. URL-encode the redirect_uri when constructing the authorize link so '&' or '=' inside it survive transport
  3. Verify no gateway/filter strips or rewrites the redirect_uri request parameter before it reaches the OAuth2 module

Example fix

// before
String url = server + "/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=" + callback;
// after
String url = server + "/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=" + URLEncoder.encode(callback, "UTF-8");
Defensive patterns

Strategy: validation

Validate before calling

boolean ok = redirectUri != null && java.util.regex.Pattern.matches("^https?://[\\w.-]+(:\\d+)?(/.*)?$", redirectUri);
if (!ok) throw new IllegalArgumentException("redirect_uri must be an absolute http(s) URL: " + redirectUri);

Try / catch

try { saOAuth2Template.checkRedirectUri(clientId, url); } catch (SaOAuth2ClientModelException e) { if (e.getCode() == 30113) return badRequest("invalid redirect_uri"); throw e; }

Prevention

When it happens

Trigger: Calling the /oauth2/authorize endpoint with a missing, empty, or malformed redirect_uri parameter (e.g. 'redirect_uri=abc', a relative path, or a value without scheme) for a registered client.

Common situations: Front-end builds the authorize link by hand and URL-encodes the redirect_uri incorrectly, or omits it entirely; a proxy/gateway strips query parameters; environment config differences between test and prod supply an incomplete URL.

Related errors


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