{"record":{"id":"75774e30e6263380","repo":"spring-projects/spring-security","slug":"digestauthenticationfilter-incorrectrealm","errorCode":"DigestAuthenticationFilter.incorrectRealm","errorMessage":"Response realm name '{0}' does not match system realm name of '{1}'","messagePattern":"Response realm name '(.+?)' does not match system realm name of '(.+?)'","errorType":"exception","errorClass":"BadCredentialsException","httpStatus":401,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java","lineNumber":375,"sourceCode":"\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}\n\t\t\t// Check nonce was Base64 encoded (as sent by DigestAuthenticationEntryPoint)\n\t\t\tfinal byte[] nonceBytes;\n\t\t\ttry {\n\t\t\t\tnonceBytes = Base64.getDecoder().decode(this.nonce.getBytes());\n\t\t\t}\n\t\t\tcatch (IllegalArgumentException ex) {\n\t\t\t\tthrow new BadCredentialsException(\n\t\t\t\t\t\tDigestAuthenticationFilter.this.messages.getMessage(\"DigestAuthenticationFilter.nonceEncoding\",\n\t\t\t\t\t\t\t\tnew Object[] { this.nonce }, \"Nonce is not encoded in Base64; received nonce {0}\"));\n\t\t\t}\n\t\t\t// Decode nonce from Base64 format of nonce is: base64(expirationTime + \":\" +\n\t\t\t// md5Hex(expirationTime + \":\" + key))\n\t\t\tString nonceAsPlainText = new String(nonceBytes);\n\t\t\tString[] nonceTokens = StringUtils.delimitedListToStringArray(nonceAsPlainText, \":\");\n\t\t\tif (nonceTokens.length != 2) {","sourceCodeStart":357,"sourceCodeEnd":393,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java#L357-L393","documentation":"validateAndDecode compares the realm sent by the client in the Digest header against the realm expected by the server (from DigestAuthenticationEntryPoint). A mismatch throws this BadCredentialsException listing both realms ({0} = client realm, {1} = expected realm), since a correct digest client echoes back the server's realm and the digest hash depends on it.","triggerScenarios":"A request's Digest header contains realm=\"X\" while the server's entry point is configured with realm=\"Y\" (the received and expected values are both in the message). E.g. client hardcodes a realm string, or the server realm was renamed.","commonSituations":"Multiple server environments (dev/prod) with different realm names but a shared client; a server-side Spring Security config change renaming the realm; hardcoded realm in scripts/mobile apps; reverse proxy fronting two apps with different realms on the same host.","solutions":["Read both realm values from the exception message and align them: change the client to use the server's realm, or update DigestAuthenticationEntryPoint's realmName to the expected one.","Prefer having the client take realm/nonce dynamically from the server's WWW-Authenticate challenge instead of hardcoding.","Grep client code/config for the old realm string and update it after any realm rename.","If two apps share a host/path space, give each a distinct path or use the same realm intentionally."],"exampleFix":"// before (server config)\nhttp.exceptionHandling().authenticationEntryPoint(new DigestAuthenticationEntryPoint()); // default/wrong realm\n// after\nDigestAuthenticationEntryPoint entryPoint = new DigestAuthenticationEntryPoint();\nentryPoint.setRealmName(\"MyAppRealm\"); // must match the realm the clients echo back","handlingStrategy":"validation","validationCode":"String serverRealm = extractRealm(conn.getHeaderField(\"WWW-Authenticate\"));\nif (!serverRealm.equals(clientConfiguredRealm)) {\n    clientConfiguredRealm = serverRealm; // use the realm the server advertises\n}\n","typeGuard":null,"tryCatchPattern":"try {\n    chain.doFilter(request, response);\n} catch (BadCredentialsException e) {\n    if (e.getMessage().contains(\"does not match system realm name\")) {\n        // parse both realms from the message and re-authenticate with the server's realm\n        response.sendError(401, \"Realm mismatch, restart auth with server challenge\");\n    }\n}","preventionTips":["Never hardcode the realm; always take it from the server's WWW-Authenticate challenge","Keep realmName identical across environments or load it from config","After renaming a realm, update all clients and clear cached credentials","Use one realm per protected application and document it"],"tags":["spring-security","digest-auth","realm-mismatch","bad-credentials"],"backgroundTag":"invalid-argument-value","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"}