user1294431
user1294431

Reputation: 635

OAuth2 with Implicit client and csrf protection

I have an API I want to secure with OAuth2. I already did a dummy test with the password grant_type and everything works. I can request tokens, access secured endpoints with it, etc. The server acts as the authorization and resource server.

Later on I read that I should be using the implicit grant_type as the client will be a javascript app.

My client is configured like so:

@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {// @formatter:off
clients
    .inMemory().withClient("web")
    .redirectUris("http://localhost:3000")
    .secret("secret")
    .authorizedGrantTypes("implicit", "refresh_token").scopes("read", "write")
    .accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(2592000);
}

If I try accessing the endpoint like this: http://localhost:8080/oauth/authorize?grant_type=implicit&client_id=web&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3A3000

I get this:

{
  "timestamp": 1464136960414,
  "status": 403,
  "error": "Forbidden",
  "message": "Expected CSRF token not found. Has your session expired?",
  "path": "/oauth/authorize"
}

How can I have a CSRF token if it's the first time I'm calling the API? If (just for testing) I disable csrf then I get this:

{
  "timestamp": 1464136840865,
  "status": 403,
  "error": "Forbidden",
  "exception": "org.springframework.security.authentication.InsufficientAuthenticationException",
  "message": "Access Denied",
  "path": "/oauth/authorize"
}

Setting the client with the password grant_type I'm able to make this call and everything works: http://localhost:8080/oauth/token?grant_type=password&username=test&password=123 And adding the Authorization Basic header with the client id/secret.

Just to clarify, the idea is to have this unique trusted client. So the user should just input login/password without asking the user to grant access rights to the app.

Sorry if this is a dumb question. I've been reading everything I can find but cannot seem to make progress with it.

Thanks!

EDIT:

My Spring Security Config:

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private MongoDBAuthenticationProvider authenticationProvider;

  @Autowired
  public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider);
  }

  @Override
  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }
}

My OAuth Config:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends     AuthorizationServerConfigurerAdapter {

  @Autowired
  @Qualifier("authenticationManagerBean")
  private AuthenticationManager authenticationManager;

  @Override
  public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
  }

  @Override
  public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
    clients
    .inMemory().withClient("web")
    .redirectUris("http://localhost:3000")
    .secret("secret")
    .authorizedGrantTypes("implicit", "refresh_token").scopes("read", "write")
    .accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(2592000);
  }

  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints)     throws Exception {
    endpoints.authenticationManager(authenticationManager);
  }  
}

Exception in Server:

2016-05-25 19:52:20.744 DEBUG 34968 --- [nio-8080-exec-5] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /oauth/authorize
2016-05-25 19:52:20.744 DEBUG 34968 --- [nio-8080-exec-5] .s.o.p.e.FrameworkEndpointHandlerMapping : Returning handler method [public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.String>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)]
2016-05-25 19:52:20.746 DEBUG 34968 --- [nio-8080-exec-5] o.s.s.w.a.ExceptionTranslationFilter     : Authentication exception occurred; redirecting to authentication entry point

org.springframework.security.authentication.InsufficientAuthenticationException: User must be authenticated with Spring Security before authorization can be completed.
at     org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(AuthorizationEndpoint.java:138) ~[spring-security-oauth2-2.0.9.RELEASE.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_40]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_40]
....

Upvotes: 0

Views: 1648

Answers (1)

Soma Yarlagadda
Soma Yarlagadda

Reputation: 2943

When you call the authorization server for implicit grant type you have to include an opaque string value as state parameter to avoid csrf attacks. So, the request url to the authorization server will look like:

http://localhost:8080/oauth/authorize?grant_type=implicit&client_id=web&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%3A3000&state=123abc

The value you mentioned in the state parameter will be echoed back to you in the response. You then compare the echoed value with initial value to confirm that there is no csrf attack happened.

Thank you, Soma.

Upvotes: 1

Related Questions