{"record":{"id":"43aa356f63f32894","repo":"spring-projects/spring-security","slug":"switchuserfilter-nooriginalauthentication","errorCode":"SwitchUserFilter.noOriginalAuthentication","errorMessage":"Failed to find original user","messagePattern":"Failed to find original user","errorType":"exception","errorClass":"AuthenticationCredentialsNotFoundException","httpStatus":null,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java","lineNumber":275,"sourceCode":"\t * @return The original <code>Authentication</code> object or <code>null</code>\n\t * otherwise.\n\t * @throws AuthenticationCredentialsNotFoundException If no\n\t * <code>Authentication</code> associated with this request.\n\t */\n\tprotected Authentication attemptExitUser(HttpServletRequest request)\n\t\t\tthrows AuthenticationCredentialsNotFoundException {\n\t\t// need to check to see if the current user has a SwitchUserGrantedAuthority\n\t\tAuthentication current = this.securityContextHolderStrategy.getContext().getAuthentication();\n\t\tif (current == null) {\n\t\t\tthrow new AuthenticationCredentialsNotFoundException(this.messages\n\t\t\t\t.getMessage(\"SwitchUserFilter.noCurrentUser\", \"No current user associated with this request\"));\n\t\t}\n\t\t// check to see if the current user did actual switch to another user\n\t\t// if so, get the original source user so we can switch back\n\t\tAuthentication original = getSourceAuthentication(current);\n\t\tif (original == null) {\n\t\t\tthis.logger.debug(\"Failed to find original user\");\n\t\t\tthrow new AuthenticationCredentialsNotFoundException(this.messages\n\t\t\t\t.getMessage(\"SwitchUserFilter.noOriginalAuthentication\", \"Failed to find original user\"));\n\t\t}\n\t\t// get the source user details\n\t\tUserDetails originalUser = null;\n\t\tObject obj = original.getPrincipal();\n\t\tif ((obj != null) && obj instanceof UserDetails) {\n\t\t\toriginalUser = (UserDetails) obj;\n\t\t}\n\t\t// publish event\n\t\tif (this.eventPublisher != null) {\n\t\t\tthis.eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(current, originalUser));\n\t\t}\n\t\treturn original;\n\t}\n\n\t/**\n\t * Create a switch user token that contains an additional <tt>GrantedAuthority</tt>\n\t * that contains the original <code>Authentication</code> object.","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/authentication/switchuser/SwitchUserFilter.java#L257-L293","documentation":"When exiting impersonation, SwitchUserFilter extracts the original Authentication from the current one via getSourceAuthentication (looking for a SwitchUserGrantedAuthority with ROLE_PREVIOUS_AUTHENTICATION). If none is present, the current user was never actually switched, and AuthenticationCredentialsNotFoundException (SwitchUserFilter.noOriginalAuthentication) is thrown.","triggerScenarios":"attemptExitUser is invoked at the exit-user URL by a user whose Authentication contains no SwitchUserGrantedAuthority — i.e. calling /logout/impersonate while not impersonating anyone.","commonSituations":"User bookmarks or manually visits the exit URL; the switch-back link is rendered to all users instead of only impersonators; successful exit already consumed the previous-authentication authority and the user clicks it again.","solutions":["Only render/allow the exit-user endpoint when the current user holds a SwitchUserGrantedAuthority","Handle AuthenticationCredentialsNotFoundException for the exit URL with a redirect to the home page instead of a 500/403","Guard the exit URL with a request check or custom filter that verifies impersonation state","Avoid double-clicking switch-back: after exit the authority is removed"],"exampleFix":"// before\nboolean canExit = authentication != null;\n// after\nboolean canExit = authentication != null && authentication.getAuthorities().stream()\n        .anyMatch(a -> a instanceof SwitchUserGrantedAuthority);","handlingStrategy":"type-guard","validationCode":"Authentication auth = SecurityContextHolder.getContext().getAuthentication();\nboolean impersonating = auth != null && auth.getAuthorities().stream()\n        .anyMatch(a -> a instanceof SwitchUserGrantedAuthority);\nif (!impersonating) {\n    response.sendRedirect(request.getContextPath() + \"/\");\n    return;\n}","typeGuard":"boolean isImpersonating(Authentication a) {\n    return a != null && a.getAuthorities().stream()\n        .anyMatch(SwitchUserGrantedAuthority.class::isInstance);\n}","tryCatchPattern":"try {\n    switchUserFilter.doFilter(request, response);\n} catch (AuthenticationCredentialsNotFoundException e) {\n    response.sendRedirect(\"/\"); // not impersonating; nothing to switch back to\n}","preventionTips":["Only expose /logout/impersonate when ROLE_PREVIOUS_AUTHENTICATION is present","Redirect rather than error when exit is requested without impersonation","Strip impersonation state on double exit attempts","Add integration tests for exit URL hit without prior switch"],"tags":["spring-security","switch-user","impersonation","authorization"],"backgroundTag":"authentication-required","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}