Secure Spring Rest API Using Spring Security Oauth2 Example

This tutorial shows you how to Secure Spring Rest API Using Spring Security Oauth2 Example. OAuth2 is an authentication framework that allows third-party applications to grant limited access to a HTTP service, either on behalf of a resource owner or by allowing the third-party application to obtain access on its own behalf.

Table of contents:
1. OAuth2 Introduction
2. Configure Resource Server
3. Configure Authorization Server
4. Spring Security Configuration
5. Spring Rest Controller
6. Deploy Secure Spring Rest API Using Spring Security Oauth2 Example

Other interesting posts you may like

OAuth2 Introduction
OAuth2 defines four roles:
Resource Owner: One user or yourself or an entity capable of granting access to a protected resource.
Resource Server: One server that stores protected resources, this server supports access token for request and response.
Authorization Server: One server that distributes access tokens to client after successfully authentication the resource owner and obtaining authorization.
Client: An application making requests to protected resources on behalf of the owner. It can be a web app server, a mobile app, a client side application. In this example, we are using DHC REST Client like a client.

We don’t introduce OAuth2 deeply here. You can refer to the completely OAuth2 tutorial. We will focus on how to create Spring Rest API Using Spring Security Oauth2 Example step by step.

Configure Resource Server
Resource Server stores the protected resources that client needs. We configure resource server by creating the custom class of ResourceServerConfigurer. Here is the code snippet.

Let’s dig deeper:
Following the above code, Resources are located on path /fruits/. @EnableResourceServer annotation eanbles a Spring Security filter that authenticates requests. These incoming requests have to include OAuth2 token.

Configure Authorization Server

Authorization server is responsible for verifying user credentials. And Authorization server will provide tokens (access-token or refresh-token) if the user credentials are valid. It also stores some other information such as registered client, access scopes and grant types. We configure the Authorization Server with the below code:

Let’s dig deeper:

@EnableAuthorizationServer annotation is used to enable an Authorization Server in the current application context. The configure(ClientDetailsServiceConfigurer clients) method configures the ClientDetailsService, e.g. declaring individual clients and their properties. The method configures the non-security features of the Authorization Server endpoints, like token store, token customizations, user approvals and grant types. The method configures the security of the Authorization Server, which means in practical terms the /oauth/token endpoint.

Spring Security Configuration
We configure spring secruity for the application by creating the WebSecurityConfigurerAdapter class that extends from the WebSecurityConfigurerAdapter class.

The globalUserDetails(AuthenticationManagerBuilder auth) method configures resource owner ( javabycode and admin user). The configure(HttpSecurity http) method configures security for the endpoint /oauth/token. We get tokens (access token and refresh token) via the endpoint /oauth/token.

Spring Rest Controller
We reuse the rest controller named FruitController from the previous post Spring Security Basic Authentication Example. You can refer it on that post or look into in source code attachment. And we don’t mention it here.

Deploy Secure Spring Rest API Using Spring Security Oauth2 Example
After building the project by maven we deploy the file war on application server (Tomcat 8 for example). We are using DHC REST client to test rest api with oauth2.

Access the URL localhost:8080/spring-oauth2-example/fruits without any authorization. The message is 401 Unauthorized like below image:

Secure Spring Rest API Using Spring Security Oauth2 Example 401

Get tokens using HTTP POST on endpoint /oauth/token with grant_type=password and resource owner like the URL localhost:8080/spring-oauth2-example/oauth/token?grant_type=password&username=admin&password=admin123. One more, you have to set Header Authorization with client credential myRestClient/P@ssw0rd. You will receive both access token and refresh token. Here is the result screen:

Secure Spring Rest API Using Spring Security Oauth2 Example token

Use the access token to request resources. Notices that the access token is valid for 2 minutes. Here is URL we you need localhost:8080/spring-oauth2-example/fruits?access_token=454b4db8-644e-4e72-bd8f-0b13f5c859fe and the screen displays like this:

Secure Spring Rest API Using Spring Security Oauth2 Example success

This access token is invalid after 2 minutes. We run this localhost:8080/spring-oauth2-example/fruits?access_token=454b4db8-644e-4e72-bd8f-0b13f5c859fe again to see this case

Secure Spring Rest API Using Spring Security Oauth2 Example 401

We get new access token by submitting a post with refresh-token. The URL looks like this: http:/localhost:8080/spring-oauth2-example/oauth/token?grant_type=refresh_token&refresh_token=5168074a-fb24-46c2-bb43-786ebd01d00f

Secure Spring Rest API Using Spring Security Oauth2 Example refresh

That’s all on the tutorial Secure Spring Rest API Using Spring Security Oauth2 Example.
If you found this useful, please share it with your friends

Download complete source code, click link below

Spring-Rest-API-Using-Spring-Security-Oauth2-Example.zip (1320 downloads)

23 thoughts on “Secure Spring Rest API Using Spring Security Oauth2 Example

  1. I deployed my spring rest api + spring security with oAuth2 in a tomcat 7.
    I created a UsersRestController with a single endpoint GET /users that fetches all the users from the db.
    I configured the security exactly how you did in your example:

    @Configuration
    @EnableResourceServer
    public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = “my_rest_api”;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
    resources.resourceId(RESOURCE_ID).stateless(false);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
    http.
    anonymous().disable()
    .requestMatchers().antMatchers(“/users/**”)
    .and()
    .authorizeRequests().antMatchers(“/users/**”).access(“hasRole(‘ADMIN’)”)
    .and()
    .exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }
    }

    The thing is that when I call GET on the /users the response is OK is the list of users. It should complain about security but I don’t understand why it works :). Do you have an idea?

    This is from the log of the server:

    INFO – questMappingHandlerMapping – Mapped “{[/users],methods=[GET],produces=[application/json]}” onto public ro.lvc.users.dto.UsersListDTO ro.lvc.users.controller.UsersController.getAllUsers()
    INFO – questMappingHandlerAdapter – Looking for @ControllerAdvice: Root WebApplicationContext: startup date [Tue Feb 07 17:26:26 CET 2017]; root of context hierarchy
    INFO – workEndpointHandlerMapping – Mapped “{[/oauth/authorize]}” onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map,java.util.Map,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
    INFO – workEndpointHandlerMapping – Mapped “{[/oauth/authorize],methods=[POST],params=[user_oauth_approval]}” onto public org.springframework.web.servlet.View org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.approveOrDeny(java.util.Map,java.util.Map,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
    INFO – workEndpointHandlerMapping – Mapped “{[/oauth/token],methods=[GET]}” onto public org.springframework.http.ResponseEntity org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.getAccessToken(java.security.Principal,java.util.Map) throws org.springframework.web.HttpRequestMethodNotSupportedException
    INFO – workEndpointHandlerMapping – Mapped “{[/oauth/token],methods=[POST]}” onto public org.springframework.http.ResponseEntity org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map) throws org.springframework.web.HttpRequestMethodNotSupportedException
    INFO – workEndpointHandlerMapping – Mapped “{[/oauth/check_token]}” onto public java.util.Map org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint.checkToken(java.lang.String)
    INFO – workEndpointHandlerMapping – Mapped “{[/oauth/confirm_access]}” onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelApprovalEndpoint.getAccessConfirmation(java.util.Map,javax.servlet.http.HttpServletRequest) throws java.lang.Exception
    INFO – workEndpointHandlerMapping – Mapped “{[/oauth/error]}” onto public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.WhitelabelErrorEndpoint.handleError(javax.servlet.http.HttpServletRequest)
    INFO – DefaultSecurityFilterChain – Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern=’/oauth/token’], Ant [pattern=’/oauth/token_key’], Ant [pattern=’/oauth/check_token’]]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@60264e48, org.springframework.security.web.context.SecurityContextPersistenceFilter@4db429f, org.springframework.security.web.header.HeaderWriterFilter@7d8784cd, org.springframework.security.web.authentication.logout.LogoutFilter@8e40e61, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@645525e, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@322b33c3, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@39a9fc93, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2009cdc5, org.springframework.security.web.session.SessionManagementFilter@33bb6d1e, org.springframework.security.web.access.ExceptionTranslationFilter@3340d40b, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@2530b288]
    INFO – DefaultSecurityFilterChain – Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern=’/users/**’]]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3ce96d6a, org.springframework.security.web.context.SecurityContextPersistenceFilter@22080b2a, org.springframework.security.web.header.HeaderWriterFilter@19359d1a, org.springframework.security.web.authentication.logout.LogoutFilter@35515a95, org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter@71ac4640, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4dcfcb6c, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@78a75282, org.springframework.security.web.session.SessionManagementFilter@1f9a542f, org.springframework.security.web.access.ExceptionTranslationFilter@360b346b, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@44847baf]
    INFO – DefaultSecurityFilterChain – Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher@1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@54dfc26c, org.springframework.security.web.context.SecurityContextPersistenceFilter@500ef978, org.springframework.security.web.header.HeaderWriterFilter@a020d0a, org.springframework.security.web.authentication.logout.LogoutFilter@584e61bb, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4ab974a4, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@50c94aa4, org.springframework.security.web.session.SessionManagementFilter@7b7e6e28, org.springframework.security.web.access.ExceptionTranslationFilter@6e3e8267, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4fdfce7a]

  2. @Configuration
    @EnableResourceServer
    public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = “SPRING_REST_API”;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
    resources.resourceId(RESOURCE_ID).stateless(false);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
    http.anonymous().disable()
    .requestMatchers().antMatchers(“/fruits/**”)
    .and().authorizeRequests()
    .antMatchers(“/fruits/**”).access(“hasRole(‘ADMIN’)”)
    .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

    }

    Hello guys, may I ask where to put the “myRestClient/P@ssw0rd”.
    Still can’t access /fruits and I’m always unauthorized.

    Thanks for the help guys.

    • You have to enable Header Authorization by click the label “set an authorization”, then put the “myRestClient/P@ssw0rd” into Authorization popup

      • You can try this with HttpClient like below:

        String plainCredential = “your-username:your-password”;
        String encoding = new String(Base64.encodeBase64(plainCredential.getBytes()));

        HttpPost httppost = new HttpPost(“http://host:port/test/login”);
        httppost.setHeader(“Authorization”, “Basic ” + encoding);

        System.out.println(“executing request ” + httppost.getRequestLine());
        HttpResponse response = httpclient.execute(httppost);
        HttpEntity entity = response.getEntity();

  3. unable to use localhost:8080/spring-oauth2-example/oauth/token?grant_type=password&username=admin&password=admin123.i have to set Header Authorization

    • Try this with HttpClient like below

      String plainCredential = “your-username:your-password”;
      String encoding = new String(Base64.encodeBase64(plainCredential.getBytes()));

      HttpPost httppost = new HttpPost(“http://host:port/test/login”);
      httppost.setHeader(“Authorization”, “Basic ” + encoding);

      System.out.println(“executing request ” + httppost.getRequestLine());
      HttpResponse response = httpclient.execute(httppost);
      HttpEntity entity = response.getEntity();

  4. +1 for excellent article.

    I have one question. What is the purpose of following two methods that you have in here?

    @Bean
    @Autowired
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
    TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
    handler.setTokenStore(tokenStore);
    handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientService));
    handler.setClientDetailsService(clientService);
    return handler;
    }

    @Bean
    @Autowired
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
    TokenApprovalStore store = new TokenApprovalStore();
    store.setTokenStore(tokenStore);
    return store;
    }

    I don’t get why you would need it.

  5. I followed everything, but i am getting Bad Credentials

    this is the request

    POST /oauth/token?grant_type=password&username=admin&password=admin123 HTTP/1.1
    Host: localhost:9999
    Authorization: Basic bXlSZXN0Q2xpZW50OlBAc3N3MHJk
    Cache-Control: no-cache
    Postman-Token: 972b66a8-e028-d40f-3d6f-71c9864e0def

Leave a Comment

*

Please share it if you found this useful
Hide Buttons