{"record":{"id":"6972867e047044e8","repo":"spring-projects/spring-security","slug":"digestauthenticationfilter-missingmandatory","errorCode":"DigestAuthenticationFilter.missingMandatory","errorMessage":"Missing mandatory digest value; received header {0}","messagePattern":"Missing mandatory digest value; received header (.+?)","errorType":"exception","errorClass":"BadCredentialsException","httpStatus":401,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java","lineNumber":360,"sourceCode":"\t\t\tthis.username = headerMap.get(\"username\");\n\t\t\tthis.realm = headerMap.get(\"realm\");\n\t\t\tthis.nonce = headerMap.get(\"nonce\");\n\t\t\tthis.uri = headerMap.get(\"uri\");\n\t\t\tthis.response = headerMap.get(\"response\");\n\t\t\tthis.qop = headerMap.get(\"qop\"); // RFC 2617 extension\n\t\t\tthis.nc = headerMap.get(\"nc\"); // RFC 2617 extension\n\t\t\tthis.cnonce = headerMap.get(\"cnonce\"); // RFC 2617 extension\n\t\t\tlogger.debug(\n\t\t\t\t\tLogMessage.format(\"Extracted username: '%s'; realm: '%s'; nonce: '%s'; uri: '%s'; response: '%s'\",\n\t\t\t\t\t\t\tthis.username, this.realm, this.nonce, this.uri, this.response));\n\t\t}\n\n\t\tvoid validateAndDecode(@Nullable String entryPointKey, @Nullable String expectedRealm)\n\t\t\t\tthrows BadCredentialsException {\n\t\t\t// Check all required parameters were supplied (ie RFC 2069)\n\t\t\tif ((this.username == null) || (this.realm == null) || (this.nonce == null) || (this.uri == null)\n\t\t\t\t\t|| (this.response == null)) {\n\t\t\t\tthrow new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage(\n\t\t\t\t\t\t\"DigestAuthenticationFilter.missingMandatory\", new Object[] { this.section212response },\n\t\t\t\t\t\t\"Missing mandatory digest value; received header {0}\"));\n\t\t\t}\n\t\t\t// Check all required parameters for an \"auth\" qop were supplied (ie RFC 2617)\n\t\t\tif (\"auth\".equals(this.qop)) {\n\t\t\t\tif ((this.nc == null) || (this.cnonce == null)) {\n\t\t\t\t\tlogger.debug(LogMessage.format(\"extracted nc: '%s'; cnonce: '%s'\", this.nc, this.cnonce));\n\t\t\t\t\tthrow new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage(\n\t\t\t\t\t\t\t\"DigestAuthenticationFilter.missingAuth\", new Object[] { this.section212response },\n\t\t\t\t\t\t\t\"Missing mandatory digest value; received header {0}\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Check realm name equals what we expected\n\t\t\tif (!this.realm.equals(expectedRealm)) {\n\t\t\t\tthrow new BadCredentialsException(DigestAuthenticationFilter.this.messages.getMessage(\n\t\t\t\t\t\t\"DigestAuthenticationFilter.incorrectRealm\", new Object[] { this.realm, expectedRealm },\n\t\t\t\t\t\t\"Response realm name '{0}' does not match system realm name of '{1}'\"));\n\t\t\t}","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java#L342-L378","documentation":"DigestAuthenticationFilter's DigestAuthHeaderDetails.validateAndDecode throws this when the Digest Authorization header is missing one of the mandatory parameters required by RFC 2069: username, realm, nonce, uri, or response. The full received header is embedded in the message ({0} = section212response) to aid debugging.","triggerScenarios":"A request carries a Digest 'Authorization' header that omits any of username, realm, nonce, uri, or response — e.g. a client sends only 'Digest username=\"x\"' or a partially-implemented digest client drops the nonce or response field.","commonSituations":"Hand-rolled or non-conformant HTTP clients; custom auth middleware that forwards a stripped-down header; proxies removing header parameters; misconfigured front-ends sending Basic-style headers while the server expects Digest; test harnesses constructing the header manually and forgetting fields.","solutions":["Compare the received header (printed in the exception message) against the full RFC 2069 parameter set and have the client include username, realm, nonce, uri, and response.","If the client is doing challenge/response, make it first consume the WWW-Authenticate challenge from the 401 and echo back all realm/nonce values it received.","Check proxies/gateways (and header sanitizers) aren't dropping or rewriting Authorization parameters.","If Digest auth isn't actually intended, switch the client to the scheme the server entry point advertises (or configure the server for Basic/Form auth instead)."],"exampleFix":"// before (manual client header)\nAuthorization: Digest username=\"admin\"\n// after\nAuthorization: Digest username=\"admin\", realm=\"Realm\", nonce=\"<from WWW-Authenticate>\", uri=\"/api\", response=\"<md5 digest>\"","handlingStrategy":"validation","validationCode":"Set<String> required = Set.of(\"username\", \"realm\", \"nonce\", \"uri\", \"response\");\nSet<String> present = parseDigestParams(authorizationHeader).keySet();\nif (!present.containsAll(required)) throw new IllegalStateException(\"Digest header missing: \" + required);\n","typeGuard":null,"tryCatchPattern":"try {\n    chain.doFilter(request, response);\n} catch (BadCredentialsException e) {\n    if (e.getMessage().startsWith(\"Missing mandatory digest value\")) {\n        response.sendError(401, \"Digest header incomplete: \" + e.getMessage());\n    }\n}","preventionTips":["Consume the WWW-Authenticate 401 challenge and echo every parameter (realm, nonce) back","Use a proven digest-auth client library rather than hand-assembling the header","Verify proxies don't strip Authorization header parameters","Unit-test your digest header against the RFC 2069 parameter list"],"tags":["spring-security","digest-auth","http-header","bad-credentials"],"backgroundTag":"missing-required-argument","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}