wuyouzhuguli/SpringAll · error · UnapprovedClientAuthenticationException

请求头中无client信息

Error message

请求头中无client信息

What it means

UnapprovedClientAuthenticationException thrown in MyAuthenticationSucessHandler.onAuthenticationSuccess when the request has no 'Authorization' header or the header does not start with 'Basic '. This handler mints an OAuth2 access token after a successful form/mobile login by treating the caller as an OAuth2 client, so it requires HTTP Basic client credentials (base64(clientId:clientSecret)).

Source

Thrown at 64.Spring-Security-OAuth2-Customize/src/main/java/cc/mrbird/security/handler/MyAuthenticationSucessHandler.java:39

import java.util.Base64;
import java.util.HashMap;

@Component
public class MyAuthenticationSucessHandler implements AuthenticationSuccessHandler {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        // 1. 从请求头中获取 ClientId
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith("Basic ")) {
            throw new UnapprovedClientAuthenticationException("请求头中无client信息");
        }

        String[] tokens = this.extractAndDecodeHeader(header, request);
        String clientId = tokens[0];
        String clientSecret = tokens[1];

        TokenRequest tokenRequest = null;

        // 2. 通过 ClientDetailsService 获取 ClientDetails
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);

        // 3. 校验 ClientId和 ClientSecret的正确性
        if (clientDetails == null) {
            throw new UnapprovedClientAuthenticationException("clientId:" + clientId + "对应的信息不存在");
        } else if (!StringUtils.equals(clientDetails.getClientSecret(), clientSecret)) {
            throw new UnapprovedClientAuthenticationException("clientSecret不正确");
        } else {
            // 4. 通过 TokenRequest构造器生成 TokenRequest

View on GitHub (pinned to 614d2578d9)

Solutions

  1. Send 'Authorization: Basic <base64(clientId:clientSecret)>' on the login request that triggers this success handler.
  2. Confirm the header literal: must start with 'Basic ' (capital B, one trailing space) before the base64 payload.
  3. Do not send a Bearer token for the login itself; the Basic client header is separate from the resulting access token.
  4. Ensure no proxy/gateway strips Authorization on the way in.

Example fix

// before
// fetch('/authentication/login', { method:'POST', body: form })

// after
const basic = btoa('clientId:clientSecret');
fetch('/authentication/login', {
  method: 'POST',
  headers: { 'Authorization': 'Basic ' + basic },
  body: form
});
Defensive patterns

Strategy: validation

Validate before calling

// Always attach the Basic client header for the login that triggers this handler.
function authHeader(clientId, secret) {
  return 'Basic ' + btoa(`${clientId}:${secret}`);
}
fetch('/authentication/form', { method:'POST', headers:{ Authorization: authHeader(CID, CSECRET) }, body: form });

Try / catch

try { await login(); }
catch (e) {
  if (/请求头中无client信息/.test(e.message)) attachBasicClientHeader();
  else handleError(e);
}

Prevention

When it happens

Trigger: A successful login request that lacks the Authorization header, or sends a Bearer token instead of Basic; the header is present but not prefixed with 'Basic ' (case/spacing sensitive, note the trailing space).

Common situations: SPA/mobile client logged in without embedding client credentials; developer used a Bearer token for the login call; the gateway stripped the Authorization header; header capitalization or missing space after 'Basic'.

Related errors


AI-assisted analysis of wuyouzhuguli/SpringAll@614d2578d9 (2026-08-14). Data as JSON: /api/errors/9954a51af321eca0. Report an issue: GitHub.