dromara/Sa-Token · error · SaOAuth2Exception
30126
30126
Error message
无效 grant_type:
What it means
Thrown by SaOAuth2ServerProcessor.clientToken: the client-credentials endpoint (/oauth2/client_token) requires grant_type=client_credentials exactly. Any other value (including authorization_code or password, which belong on /oauth2/token) is rejected before config and client checks run. Error code 30126.
Source
Thrown at sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/processor/SaOAuth2ServerProcessor.java:301
}
// 默认返回
throw new SaOAuth2Exception("无效response_type: " + ra.responseType).setCode(SaOAuth2ErrorCode.CODE_30125);
}
/**
* 模式四:凭证式
* @return 处理结果
*/
public Object clientToken() {
// 获取变量
SaRequest req = SaHolder.getRequest();
SaOAuth2ServerConfig cfg = SaOAuth2Manager.getServerConfig();
SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();
String grantType = req.getParamNotNull(Param.grant_type);
if(!grantType.equals(GrantType.client_credentials)) {
throw new SaOAuth2Exception("无效 grant_type:" + grantType).setCode(SaOAuth2ErrorCode.CODE_30126);
}
if(!cfg.enableClientCredentials) {
throwErrorSystemNotEnableModel();
}
if(!currClientModel().getAllowGrantTypes().contains(GrantType.client_credentials)) {
throwErrorClientNotEnableModel();
}
// 获取参数
ClientIdAndSecretModel clientIdAndSecret = SaOAuth2Manager.getDataResolver().readClientIdAndSecret(req);
String clientId = clientIdAndSecret.clientId;
String clientSecret = clientIdAndSecret.clientSecret;
List<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(req.getParam(Param.scope));
// 校验 ClientScope
oauth2Template.checkContractScope(clientId, scopes);
// 校验 ClientSecretView on GitHub (pinned to ac2c7f6e94)
Solutions
- Use grant_type=client_credentials on /oauth2/client_token
- For authorization_code or password grants, call /oauth2/token instead
- Trim and verify the exact spelling of grant_type before sending
Example fix
# before curl -X POST http://host/oauth2/client_token -d 'grant_type=password&username=x&password=y' # after curl -X POST http://host/oauth2/client_token \ -u 1001:secret -d 'grant_type=client_credentials&scope=all'
Defensive patterns
Strategy: validation
Validate before calling
if(!"client_credentials".equals(grantType)) {
throw new IllegalArgumentException("/oauth2/client_token only accepts grant_type=client_credentials");
} Try / catch
catch(SaOAuth2Exception e) { if("30126".equals(e.getCode())) return badRequest("invalid grant_type for this endpoint"); } Prevention
- Use one token-client class per grant type so endpoints cannot be mixed up
- Document endpoint-to-grant-type mapping next to client credential config
When it happens
Trigger: POST /oauth2/client_token with grant_type=password or grant_type=authorization_code; grant_type missing or misspelled (e.g. 'clientcredential').
Common situations: Developer points all token requests at the wrong endpoint; copy-pasted token request from password flow reused against client_token; trailing whitespace in the parameter.
Related errors
AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14).
Data as JSON: /api/errors/c682d3742c67370a.
Report an issue: GitHub.