paascloud/paascloud-master · error · UnapprovedClientAuthenticationException
请求头中无client信息
Error message
请求头中无client信息
What it means
UnapprovedClientAuthenticationException (Spring Security OAuth) with message '请求头中无client信息' thrown by UacUserLoginController.refreshToken when the HTTP Authorization header is absent or does not start with the 'Basic ' (BEARER_TOKEN_TYPE constant as used here) prefix. The controller requires a Basic-auth client header to identify the OAuth2 client before refreshing a token.
Solutions
- Send an HTTP Basic Authorization header with base64(clientId:clientSecret), e.g. Authorization: Basic Y2xpZW50SWQ6c2VjcmV0
- Verify the gateway/proxy forwards the Authorization header to the UAC service
- Confirm the OAuth client id/secret configured in the frontend match a registered ClientDetails
- Check the expected header prefix in this codebase (BEARER_TOKEN_TYPE constant) and match it exactly
Example fix
// before request without Authorization header // after Authorization: Basic bWFsbC1hZG1pbjphZG1pbg== // base64(clientId:clientSecret)
Defensive patterns
Strategy: try-catch
Validate before calling
const header = headers['Authorization'];
if (!header || !header.startsWith('Basic ')) { failFast('missing Basic Authorization header'); } Type guard
function hasBasicAuth(header) { return typeof header === 'string' && header.startsWith('Basic '); } Try / catch
try { await refreshToken(token, headers); }
catch (e) {
if (String(e.message).includes('client信息')) {
// re-login or re-attach Basic auth credentials
}
} Prevention
- Always send Authorization: Basic base64(clientId:clientSecret) on token refresh calls
- Verify proxies/gateways forward the Authorization header
- Centralize token-refresh logic so headers are never forgotten
- Check CORS preflight does not strip Authorization
When it happens
Trigger: POST to the refreshToken endpoint without an Authorization header, or with a header not starting with the expected prefix (e.g. sending only the access token as a bare header, or 'Bearer xxx' instead of Basic base64(clientId:clientSecret)).
Common situations: Frontend strips the Authorization header via a proxy or CORS preflight handling; developer sends the access token without Basic client credentials; gateway removes auth headers; client credentials missing in mobile/SPA configuration.
Related errors
AI-assisted analysis of paascloud/paascloud-master@781281a950 (2026-09-10).
Data as JSON: /api/errors/f717687b181c8f90.
Report an issue: GitHub.
Appendix: source
Thrown at paascloud-provider/paascloud-provider-uac/src/main/java/com/paascloud/provider/web/admin/UacUserLoginController.java:109
/**
* 刷新token.
*
* @param request the request
* @param refreshToken the refresh token
* @param accessToken the access token
*
* @return the wrapper
*/
@GetMapping(value = "/auth/user/refreshToken")
@ApiOperation(httpMethod = "POST", value = "刷新token")
public Wrapper<String> refreshToken(HttpServletRequest request, @RequestParam(value = "refreshToken") String refreshToken, @RequestParam(value = "accessToken") String accessToken) {
String token;
try {
Preconditions.checkArgument(org.apache.commons.lang3.StringUtils.isNotEmpty(accessToken), "accessToken is null");
Preconditions.checkArgument(org.apache.commons.lang3.StringUtils.isNotEmpty(refreshToken), "refreshToken is null");
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header == null || !header.startsWith(BEARER_TOKEN_TYPE)) {
throw new UnapprovedClientAuthenticationException("请求头中无client信息");
}
String[] tokens = RequestUtil.extractAndDecodeHeader(header);
assert tokens.length == 2;
String clientId = tokens[0];
String clientSecret = tokens[1];
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
if (clientDetails == null) {
throw new UnapprovedClientAuthenticationException("clientId对应的配置信息不存在:" + clientId);
} else if (!StringUtils.equals(clientDetails.getClientSecret(), clientSecret)) {
throw new UnapprovedClientAuthenticationException("clientSecret不匹配:" + clientId);
}
token = uacUserTokenService.refreshToken(accessToken, refreshToken, request);
} catch (Exception e) {
logger.error("refreshToken={}", e.getMessage(), e);View on GitHub (pinned to 781281a950)