First, I would recommend you check out the samples in the spring-authorization-server project itself (see this line, for example), which will ensure you're keeping up with the rapid changes occurring in the project, as those tutorials on the web will tend to get out of date quickly.
Second, I believe the 2nd error in debug is not related to this issue, so that seems like a local setup issue, but I'm not 100% sure.
Third, the first error is happening on newer versions of SAS, due to #243. The change included incorporating recommendations from OAuth 2.1, Section 9.7.1, which states:
While redirect URIs using localhost (i.e.,
"http://localhost:{port}/{path}") function similarly to loopback IP
redirects described in Section 10.3.3, the use of "localhost" is NOT
RECOMMENDED. Specifying a redirect URI with the loopback IP literal
rather than "localhost" avoids inadvertently listening on network
interfaces other than the loopback interface. It is also less
susceptible to client-side firewalls and misconfigured host name
resolution on the user's device.
This error only shows up on the redirect back to the client application, when the redirect URI has a host of localhost
. If you enable trace logging in the authorization server (e.g. logging.level.org.springframework.security=trace
) you will see a successful authentication, followed by a redirect to an error page, something like:
...
2021-08-10 11:10:41.596 DEBUG 90071 --- [io-9000-exec-10] w.a.UsernamePasswordAuthenticationFilter : Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=user, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_PILOT]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=3786957448CCBB82DAE6AB29DBCA5D2C], Granted Authorities=[ROLE_USER]]
2021-08-10 11:10:41.596 DEBUG 90071 --- [io-9000-exec-10] o.s.s.web.DefaultRedirectStrategy : Redirecting to http://auth-server:9000/error?response_type=code&client_id=messaging-client&scope=openid&state=Vg-fUjLSdOjAG_4Y9LcjcxxYTGhd33Trbaclp92XoDQ%3D&redirect_uri=http://localhost:8080/login/oauth2/code/messaging-client&nonce=s8hJD_zDopreLImNeRwQ3fslL4yFNySjbt6MiYK1mPw
...
This tells me there's something happened earlier in the flow, and we're only experiencing the symptom at this point. If you look higher up in the logs, prior to logging in, you'll see something like this:
...
2021-08-10 11:10:37.444 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy : Invoking OAuth2AuthorizationEndpointFilter (6/24)
2021-08-10 11:10:37.444 TRACE 90071 --- [nio-9000-exec-8] o.s.s.authentication.ProviderManager : Authenticating request with OAuth2AuthorizationCodeRequestAuthenticationProvider (1/10)
2021-08-10 11:10:37.445 TRACE 90071 --- [nio-9000-exec-8] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match request to [Is Secure]
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-08-10 11:10:37.445 DEBUG 90071 --- [nio-9000-exec-8] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2021-08-10 11:10:37.447 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer$$Lambda$603/0x000000080041a040@4dd90166, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@52227eb2, org.springframework.security.web.context.SecurityContextPersistenceFilter@21263314, org.springframework.security.web.header.HeaderWriterFilter@4d84049a, org.springframework.security.web.csrf.CsrfFilter@1d8b0500, org.springframework.security.web.authentication.logout.LogoutFilter@6413d7e7, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter@32d5279, org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter@fe87ddd, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter@448b808a, org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter@ebda593, org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter@22d322f5, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@4337afd, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@d16be4f, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@5ad1904f, org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@60e06f7d, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4a92c6a9, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@64c781a9, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@a146b11, org.springframework.security.web.session.SessionManagementFilter@642857e0, org.springframework.security.web.access.ExceptionTranslationFilter@30c3ae63, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@550e9be6, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter@32ec9c90, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenIntrospectionEndpointFilter@456bcb74, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter@3b332962, org.springframework.security.oauth2.server.authorization.oidc.web.OidcClientRegistrationEndpointFilter@58a2d9f9]] (1/2)
2021-08-10 11:10:37.447 TRACE 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1b01a0d, org.springframework.security.web.context.SecurityContextPersistenceFilter@91f565d, org.springframework.security.web.header.HeaderWriterFilter@67b355c8, org.springframework.security.web.csrf.CsrfFilter@79f90a3a, org.springframework.security.web.authentication.logout.LogoutFilter@414f87a9, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@6e31d989, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@1ddc6db2, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@2ed71727, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@46e3559f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@3b83459e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5261ec9, org.springframework.security.web.session.SessionManagementFilter@388623ad, org.springframework.security.web.access.ExceptionTranslationFilter@22bdb1d0, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@416d56f2]] (2/2)
2021-08-10 11:10:37.447 DEBUG 90071 --- [nio-9000-exec-8] o.s.security.web.FilterChainProxy : Securing GET /error?response_type=code&client_id=messaging-client&scope=openid&state=Vg-fUjLSdOjAG_4Y9LcjcxxYTGhd33Trbaclp92XoDQ%3D&redirect_uri=http://localhost:8080/login/oauth2/code/messaging-client&nonce=s8hJD_zDopreLImNeRwQ3fslL4yFNySjbt6MiYK1mPw
...
So the error actually happens in OAuth2AuthorizationEndpointFilter
and the error redirect gets saved as the target URL after authentication, then we're redirected to /login
, and after authentication redirected back to /error
, which generates a whitelabel error page.
The short term fix would be to ensure you are using 127.0.0.1
for your client application, instead of localhost
, including changing the redirect URIs in your authorization server (see sample). But if you forget and launch your browser at http://localhost:8080
, you'll still get this error. You can work around that for now with a filter in your client application like this:
/**
* This filter ensures that the loopback IP <code>127.0.0.1</code> is used to access the
* application so that the sample works correctly, due to the fact that redirect URIs with
* "localhost" are rejected by the Spring Authorization Server, because the OAuth 2.1
* draft specification states:
*
* <pre>
* While redirect URIs using localhost (i.e.,
* "http://localhost:{port}/{path}") function similarly to loopback IP
* redirects described in Section 10.3.3, the use of "localhost" is NOT
* RECOMMENDED.
* </pre>
*
* @see <a href=
* "https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-01#section-9.7.1">Loopback Redirect
* Considerations in Native Apps</a>
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoopbackIpRedirectFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request.getServerName().equals("localhost")) {
UriComponents uri = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request))
.host("127.0.0.1").build();
response.sendRedirect(uri.toUriString());
return;
}
filterChain.doFilter(request, response);
}
}
I would encourage you to open an issue to request an improvement to the way this error is handled. And if you're interested, we'd love to discuss it with you and get you involved in the project to help with this issue.