{"record":{"id":"d27ba4957fc8043f","repo":"apache/hadoop","slug":"invalid-spnego-sequence-www-authenticate-header","errorCode":null,"errorMessage":"Invalid SPNEGO sequence, 'WWW-Authenticate' header incorrect: {}","messagePattern":"Invalid SPNEGO sequence, 'WWW-Authenticate' header incorrect: (.+?)","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java","lineNumber":396,"sourceCode":"    String token = base64.encodeToString(outToken);\n    conn.setRequestMethod(AUTH_HTTP_METHOD);\n    conn.setRequestProperty(AUTHORIZATION, NEGOTIATE + \" \" + token);\n    conn.connect();\n  }\n\n  /*\n  * Retrieves the Kerberos token returned by the server.\n  */\n  private byte[] readToken(HttpURLConnection conn)\n      throws IOException, AuthenticationException {\n    int status = conn.getResponseCode();\n    if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_UNAUTHORIZED) {\n      String authHeader = conn.getHeaderField(WWW_AUTHENTICATE);\n      if (authHeader == null) {\n        authHeader = conn.getHeaderField(WWW_AUTHENTICATE.toLowerCase());\n      }\n      if (authHeader == null || !authHeader.trim().startsWith(NEGOTIATE)) {\n        throw new AuthenticationException(\"Invalid SPNEGO sequence, '\" + WWW_AUTHENTICATE +\n                                          \"' header incorrect: \" + authHeader);\n      }\n      String negotiation = authHeader.trim().substring((NEGOTIATE + \" \").length()).trim();\n      return base64.decode(negotiation);\n    }\n    throw new AuthenticationException(\"Invalid SPNEGO sequence, status code: \" + status);\n  }\n\n}\n","sourceCodeStart":378,"sourceCodeEnd":406,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/client/KerberosAuthenticator.java#L378-L406","documentation":"During SPNEGO, KerberosAuthenticator.readToken expects the server's 200/401 response to carry a 'WWW-Authenticate: Negotiate ...' header containing the GSS continuation token. If the header is missing entirely or does not start with 'Negotiate', the handshake cannot proceed and AuthenticationException('Invalid SPNEGO sequence, ... header incorrect: ...') is thrown, including the offending/absent header value. Root cause is almost always that the endpoint is not actually doing Kerberos at the HTTP layer.","triggerScenarios":"Server configured with authentication.type=simple/pseudo (or anonymous allowed) so the 200 response carries no WWW-Authenticate header; a reverse proxy strips or rewrites WWW-Authenticate; the URL hits a static/error page instead of the SPNEGO-protected endpoint; server is a non-Kerberos service (e.g. a form-login app) returning 200 HTML.","commonSituations":"Client uses KerberosAuthenticator against a service whose hadoop-auth filter is 'simple'; httpfs/NameNode UI behind Apache/nginx that does not forward the Negotiate challenge; DNS alias vs. SPN mismatch causing the server to skip Negotiate; firewalls/injected proxies replacing 401 challenges with an HTML login page (200).","solutions":["Confirm the server side really offers Kerberos: curl -v --negotiate -u : http://host:port/ must show 'WWW-Authenticate: Negotiate' in the 401 challenge.","Set the service's authentication.type to kerberos (hadoop-auth filter config) and restart, so challenges are emitted.","Fix the reverse proxy to pass WWW-Authenticate through (nginx: proxy_pass_header WWW-Authenticate; Apache: appropriate Header directives) or bypass it for testing.","Verify you hit the intended endpoint/port, not a redirect-to-login or default page.","If a 200-no-header case persists, disable anonymous auth on the server so it always issues the challenge."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-flight: server must offer Negotiate\nHttpURLConnection probe = (HttpURLConnection) url.openConnection();\nint rc = probe.getResponseCode();\nString challenge = probe.getHeaderField(\"WWW-Authenticate\");\nboolean spnegoReady = (rc == 401 || rc == 200) && challenge != null && challenge.startsWith(\"Negotiate\");","typeGuard":null,"tryCatchPattern":"try {\n  new KerberosAuthenticator().authenticate(url, token);\n} catch (AuthenticationException e) {\n  if (e.getMessage().contains(\"header incorrect\")) {\n    // endpoint not SPNEGO-enabled or proxy stripped the challenge: fix server/proxy config\n    throw new IllegalStateException(\"Server does not offer SPNEGO at \" + url, e);\n  }\n  throw e;\n}","preventionTips":["Verify with curl -v --negotiate -u : <url> before blaming the client.","Configure reverse proxies to pass WWW-Authenticate headers untouched.","Keep server authentication.type=kerberos wherever KerberosAuthenticator clients connect."],"tags":["kerberos","spnego","negotiate","www-authenticate","hadoop-auth","authentication"],"backgroundTag":"spnego-negotiate-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}