{"record":{"id":"deb31ebe8260c1bf","repo":"spring-projects/spring-security","slug":"could-not-find-original-authentication-object","errorCode":null,"errorMessage":"Could not find original Authentication object","messagePattern":"Could not find original Authentication object","errorType":"exception","errorClass":"AuthenticationCredentialsNotFoundException","httpStatus":null,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/server/authentication/SwitchUserWebFilter.java","lineNumber":234,"sourceCode":"\tprotected @Nullable String getUsername(ServerWebExchange exchange) {\n\t\treturn exchange.getRequest().getQueryParams().getFirst(SPRING_SECURITY_SWITCH_USERNAME_KEY);\n\t}\n\n\tprivate @NonNull Mono<Authentication> attemptSwitchUser(Authentication currentAuthentication,\n\t\t\t@Nullable String userName) {\n\t\tAssert.notNull(userName, \"The userName can not be null.\");\n\t\tthis.logger.debug(LogMessage.format(\"Attempting to switch to user [%s]\", userName));\n\t\treturn this.userDetailsService.findByUsername(userName)\n\t\t\t.switchIfEmpty(Mono.error(this::noTargetAuthenticationException))\n\t\t\t.doOnNext(this.userDetailsChecker::check)\n\t\t\t.map((userDetails) -> createSwitchUserToken(userDetails, currentAuthentication));\n\t}\n\n\tprivate @NonNull Authentication attemptExitUser(Authentication currentAuthentication) {\n\t\tOptional<Authentication> sourceAuthentication = extractSourceAuthentication(currentAuthentication);\n\t\tif (sourceAuthentication.isEmpty()) {\n\t\t\tthis.logger.debug(\"Failed to find original user\");\n\t\t\tthrow noOriginalAuthenticationException();\n\t\t}\n\t\treturn sourceAuthentication.get();\n\t}\n\n\tprivate Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) {\n\t\tServerWebExchange exchange = webFilterExchange.getExchange();\n\t\tSecurityContextImpl securityContext = new SecurityContextImpl(authentication);\n\t\treturn this.securityContextRepository.save(exchange, securityContext)\n\t\t\t.doOnSuccess((v) -> this.logger.debug(LogMessage.format(\"Switched user to %s\", authentication)))\n\t\t\t.then(this.successHandler.onAuthenticationSuccess(webFilterExchange, authentication))\n\t\t\t.contextWrite(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(securityContext)));\n\t}\n\n\tprivate Mono<Void> onAuthenticationFailure(AuthenticationException exception, WebFilterExchange webFilterExchange) {\n\t\treturn Mono.justOrEmpty(this.failureHandler).switchIfEmpty(Mono.defer(() -> {\n\t\t\tthis.logger.debug(\"Failed to switch user\", exception);\n\t\t\treturn Mono.error(exception);\n\t\t})).flatMap((failureHandler) -> failureHandler.onAuthenticationFailure(webFilterExchange, exception));","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/server/authentication/SwitchUserWebFilter.java#L216-L252","documentation":"SwitchUserWebFilter's attemptExitUser tries to recover the original (pre-impersonation) Authentication by unwrapping the current 'switched user' token. When the current authentication is not a SwitchUserAuthentication (or carries no source authentication), no original user can be found and a UsernameNotFoundException-based 'Could not find original Authentication object' error is thrown, aborting the exit-user (switch back) flow.","triggerScenarios":"Calling the exit-user URL (default /logout/impersonate or configured switchUserUrl) while the current authentication is NOT an impersonation session — e.g. the user was never switched, the session expired and was re-authenticated normally, or the security context was rebuilt from a persistent login that lost the SwitchUserAuthentication wrapper.","commonSituations":"Users bookmarking the exit-impersonation URL, application restarts with persistent remember-me that don't preserve switch-user state, manual removal of the principal from the session, or hitting exit-impersonate after already exiting.","solutions":["Only expose the exit-impersonation link when the current principal is a SwitchUserAuthentication","Handle the exception and redirect the user to the home page instead of the exit URL when not impersonating","Ensure session persistence keeps the SwitchUserAuthentication across restarts, or re-impersonate explicitly","Guard with a check of the principal type before linking/invoking exit-user"],"exampleFix":"// before: always render exit link\n<a href=\"/logout/impersonate\">Exit impersonation</a>\n// after\n<span th:if=\"${principal instanceof T(org.springframework.security.web.authentication.switchuser.SwitchUserAuthenticationToken)}\">\n  <a href=\"/logout/impersonate\">Exit impersonation</a>\n</span>","handlingStrategy":"type-guard","validationCode":"boolean isImpersonating = SecurityContextHolder.getContext().getAuthentication()\n    instanceof SwitchUserAuthenticationToken;\nif (!isImpersonating) { /* hide / disable exit-impersonation flow */ }","typeGuard":"static boolean isSwitchedUser(Authentication auth) {\n    return auth instanceof SwitchUserAuthenticationToken;\n}","tryCatchPattern":null,"preventionTips":["Only render the exit-impersonation link for SwitchUserAuthenticationToken principals","Remember persistent login mechanisms may lose the switch-user wrapper after restarts","Handle the error and redirect home rather than looping users into a broken exit URL"],"tags":["switch-user","impersonation","webflux","authentication"],"backgroundTag":"invalid-state-transition","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}