{"record":{"id":"1cba467cf1022ad9","repo":"dromara/Sa-Token","slug":"30191","errorCode":"30191","errorMessage":"请提供 client 信息","messagePattern":"请提供 client 信息","errorType":"validation","errorClass":"SaOAuth2Exception","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/resolver/SaOAuth2DataResolverDefaultImpl.java","lineNumber":80,"sourceCode":"\n        // 如果请求参数中没有提供 client_id 参数，则尝试从 Authorization 中获取\n        String authorizationValue = SaHttpBasicUtil.getAuthorizationValue();\n        if(SaFoxUtil.isNotEmpty(authorizationValue)) {\n            String[] arr = authorizationValue.split(\":\");\n            clientId = arr[0];\n            if(arr.length > 1) {\n                clientSecret = arr[1];\n            }\n            return new ClientIdAndSecretModel(clientId, clientSecret);\n        }\n\n        // 如果只提供了 clientId 参数，也为其构建一个 ClientIdAndSecretModel 对象，clientSecret 置空\n        if(SaFoxUtil.isNotEmpty(clientId)) {\n            return new ClientIdAndSecretModel(clientId, null);\n        }\n\n        // 如果都没有提供，则抛出异常\n        throw new SaOAuth2Exception(\"请提供 client 信息\").setCode(SaOAuth2ErrorCode.CODE_30191);\n    }\n\n    /**\n     * 数据读取：从请求对象中读取 AccessToken，获取不到返回 null，获取不到返回 null\n     * <br /> 1、请求参数 access_token，2、请求头 Authorization Bearer access_token\n     */\n    @Override\n    public String readAccessToken(SaRequest request) {\n        // 优先从请求参数中获取，可以读取到的话直接返回\n        String accessToken = request.getParam(Param.access_token);\n        if(SaFoxUtil.isNotEmpty(accessToken)) {\n            return accessToken;\n        }\n\n        // 如果请求参数中没有提供 access_token 参数，则尝试从 Authorization 中获取\n        String authorizationValue = request.getHeader(Param.Authorization);\n        if(SaFoxUtil.isEmpty(authorizationValue)) {\n            return null;","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/data/resolver/SaOAuth2DataResolverDefaultImpl.java#L62-L98","documentation":"Thrown by SaOAuth2DataResolverDefaultImpl.readClientIdAndSecret() when the request contains neither a Basic Authorization header with client credentials nor a client_id parameter. The resolver supports three input styles: HTTP Basic (client_id:client_secret base64), a single client_id param, or neither — and the last case is rejected. Error code 30191.","triggerScenarios":"Calling /oauth2/token or /oauth2/client_token without client_id in the body/query and without an Authorization: Basic ... header. Also when a custom Authorization header scheme (e.g. Bearer) is sent where Basic was expected.","commonSituations":"Client switched from Basic auth to body params but dropped client_id entirely; a gateway rewrites or strips the Authorization header; the base64 Basic value is malformed so parsing yields nothing.","solutions":["Send client_id (and client_secret) as request parameters on the token endpoint","Or send an Authorization: Basic base64(client_id:client_secret) header","Check proxies/gateways between client and server are not stripping the Authorization header"],"exampleFix":"// before\ncurl -X POST http://host/oauth2/token -d 'grant_type=client_credentials'\n\n// after\ncurl -X POST http://host/oauth2/token \\\n  -u 1001:aaaa-bbbb-cccc-dddd-eeee \\\n  -d 'grant_type=client_credentials'","handlingStrategy":"validation","validationCode":"// client side, before calling token endpoint\nString auth = Base64.getEncoder().encodeToString((clientId + \":\" + clientSecret).getBytes());\nhttpPost.header(\"Authorization\", \"Basic \" + auth);","typeGuard":null,"tryCatchPattern":"catch(SaOAuth2Exception e) { if(\"30191\".equals(e.getCode())) return badRequest(\"provide client credentials via Basic auth or client_id param\"); }","preventionTips":["Wrap token-endpoint calls in one HTTP client helper that always attaches credentials","Log outbound Authorization headers (names only) when debugging gateway issues"],"tags":["oauth2","client-credentials","basic-auth","sa-token"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}