I'm currently working on a project where we want the user to sign in via Facebook and other OAuth2 providers. Furthermore the REST api should be stateless. Therefore no cookies/jsessionids should be created/utilized. For authorization against the api, a JWT is issued by the api after a successful sign in via Facebook. The webapp consuming the rest api is build with AgularJS and satellizer. I reduced my code to a minimal example available on github.
Workflow idea:
Working so far
The problem
The combination of webapp and the rest api's "login/facebook?code=XXX" call does not work. I found out that when you do a GET "login/facebook", you will be redirected to facebook with an additional state parameter attached to the url. Furthermore, this state parameter is also added when facebook redirects back to the api. From what I found online, this seems to be a kind of CSRF protection, right? And I guess this stuff is also creating the jsessionid cookie?
Questions
Example Code
As already mentioned, I put a complete working minimal example on GitHub. Here I will only post the (hopefully) most important part of WebSecurityConfigurerAdapter. The complete file is here.
@EnableOAuth2Client
@Configuration
public class OAuth2ClientConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).enableSessionUrlRewriting(false).and()
.antMatcher("/**").authorizeRequests()
.antMatchers("/login/**").permitAll()
.anyRequest().authenticated().and()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and()
.addFilterBefore(statelessJwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(createSsoFilter(facebook(), facebookSuccessHandler(), "/login/facebook"), BasicAuthenticationFilter.class);
}
private OAuth2ClientAuthenticationProcessingFilter createSsoFilter(ClientResourceDetails clientDetails, AuthenticationSuccessHandler successHandler, String path) {
OAuth2ClientAuthenticationProcessingFilter ssoFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
ssoFilter.setAllowSessionCreation(false);
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(clientDetails.getClient(), oAuth2ClientContext);
ssoFilter.setRestTemplate(restTemplate);
ssoFilter.setTokenServices(new UserInfoTokenServices(clientDetails.getResource().getUserInfoUri(), clientDetails.getClient().getClientId()));
ssoFilter.setAuthenticationSuccessHandler(successHandler);
return ssoFilter;
}
@Bean // handles the redirect to facebook
public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
Many thanks for your help!
OAuth2 is a framework protocol. There is no notion of server "state" in the specification.
Stateless Authentication (One-Time) When a user navigates to the backend authorization URL /oauth2/authorization/auth0 , a JSESSIONID cookie is returned in the HTTP (302) response. The user then goes on to approve or deny the authentication request on the external provider's website.
Spring Security OAuth2 project is currently deprecated and Spring Security team has decided to no longer provide support for authorization servers.
This is an optional but recommended OAuth 2.0 feature. It enforced by the authorization server and as you assumed its purpose is to prevent csrf attacks.
Copied from the OAuth 2.0 RFC:
state
RECOMMENDED. An opaque value used by the client to maintain
state between the request and callback. The authorization
server includes this value when redirecting the user-agent back
to the client. The parameter SHOULD be used for preventing
cross-site request forgery as described in Section 10.12.
https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With