Spring Security Java API

Sample Project

Download a sample project specific to this tutorial configured with your Auth0 API Keys.

System Requirements
  • Java 7 or above
  • Maven 3.0.x or above
Show requirements

This tutorial shows you how to protect your Spring Security API endpoints and limit access to resources in your API.

Create an API

Create a new API in the APIs section of the Auth0 dashboard.

Enter a name and an identifier for the API. These values represent the auth0.apiAudience value in the configuration file.

Select the signing algorithm. In the Settings tab, you can change the token expiration time and allow to refresh a token for that API. In the Scopes tab, add scopes you will use later to limit access to resources in your API.

In this tutorial, the example API contains the Photos resource. The scopes shown on the screenshot below will be used to limit access to PhotosController.

Install the Dependencies

Add the auth0-spring-security-api dependency.

If you are using Maven, add the dependency to your pom.xml file:

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>auth0-spring-security-api</artifactId>
  <version>1.0.0-rc.2</version>
</dependency>

If you are using Gradle, add the dependency to the dependencies block:

compile 'com.auth0:auth0-spring-security-api:1.0.0-rc.2'

Configure Your Spring Security API

Your Spring Security API needs some information to authenticate against your Auth0 account.

The sample project you can download from the top of this page comes with a configuration file. You may need to update some of the entries with the values for your API. The filename is /src/main/resources/auth0.properties and it contains the following:

auth0.issuer:https://YOUR_AUTH0_DOMAIN/
auth0.apiAudience:{YOUR_API_IDENTIFIER}
Attribute Description
auth0.issuer The issuer of the JWT Token. Typically, this is your Auth0 domain with a https:// prefix and a / suffix. For example, if your Auth0 domain is example.auth0.com, the auth0.issuer must be set to https://example.auth0.com/ (the trailing slash is important).
auth0.apiAudience The unique identifier for your API. You can find the correct value in the APIs section in your Auth0 dashboard.

If you download the sample project, the issuer attribute is filled out for you. You must manually set the apiAudience attribute.

Configure JSON Web Token Signature Algorithm

Configure your API to use the RS256 signing algorithm.

If you download the sample project, the signing algorithm is set to RS256 by default.

// src/main/java/com/auth0/example/AppConfig.java

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value(value = "${auth0.apiAudience}")
    private String apiAudience;
    @Value(value = "${auth0.issuer}")
    private String issuer;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtWebSecurityConfigurer
                .forRS256(apiAudience, issuer)
                .configure(http);
    }
}

Configure the Protected Endpoints

The example below shows how to implement CRUD (create, read, update and delete) methods and a login route for the Photos resource.

For CRUD methods, you need authentication and specific scopes.

In the AppConfig class, add route matchers to the snippet. The hasAuthority() method provides a way to specify the required scope for the resource.

The routes shown below are available for the following requests:

  • GET /login: available for non-authenticated requests
  • GET /photos: available for authenticated requests containing an access token with the read:photos scope granted
  • POST /photos: available for authenticated requests containing an access token with the create:photos scope granted
  • PUT /photos: available for authenticated requests containing an access token with the update:photos scope granted
  • DELETE /photos: available for authenticated requests containing an access token with the delete:photos scope granted
  • Any other route that doesn't match the above requires the user to be authenticated with no additional scopes
// src/main/java/com/auth0/example/AppConfig.java

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value(value = "${auth0.apiAudience}")
    private String apiAudience;
    @Value(value = "${auth0.issuer}")
    private String issuer;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtWebSecurityConfigurer
                .forRS256(apiAudience, issuer)
                .configure(http)
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/login").permitAll()
                .antMatchers(HttpMethod.GET, "/photos/**").hasAuthority("read:photos")
                .antMatchers(HttpMethod.POST, "/photos/**").hasAuthority("create:photos")
                .antMatchers(HttpMethod.PUT, "/photos/**").hasAuthority("update:photos")
                .antMatchers(HttpMethod.DELETE, "/photos/**").hasAuthority("delete:photos")
                .anyRequest().authenticated();
    }
}

Create the Photos Controller

Create a new class called PhotosController to handle each request to the endpoints.

Next, in the AppConfig.java file, configure which endpoints are secure and which are not.

Use the API

To test your endpoints, start the API and send the relevant HTTP requests.

// src/main/java/com/auth0/example/PhotosController.java

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@Component
public class PhotosController {

    @RequestMapping(value = "/login")
    @ResponseBody
    public String login() {
        return "All good. You DO NOT need to be authenticated to call /login";
    }

    @RequestMapping(value = "/photos", method = RequestMethod.GET)
    @ResponseBody
    public String getPhotos() {
        return "All good. You can see this because you are Authenticated with a Token granted the 'read:photos' scope";
    }

    @RequestMapping(value = "/photos", method = RequestMethod.POST)
    @ResponseBody
    public String createPhotos() {
        return "All good. You can see this because you are Authenticated with a Token granted the 'create:photos' scope";
    }

    @RequestMapping(value = "/photos", method = RequestMethod.PUT)
    @ResponseBody
    public String updatePhotos() {
        return "All good. You can see this because you are Authenticated with a Token granted the 'update:photos' scope";
    }

    @RequestMapping(value = "/photos", method = RequestMethod.DELETE)
    @ResponseBody
    public String deletePhotos() {
        return "All good. You can see this because you are Authenticated with a Token granted the 'delete:photos' scope";
    }

    @RequestMapping(value = "/**")
    @ResponseBody
    public String anyRequest() {
        return "All good. You can see this because you are Authenticated.";
    }

}

To build and run the seed project, use the command: mvn spring-boot:run.

To test a non-secure endpoint, send a GET request to http://localhost:3001/login.

curl -X GET -H "Content-Type: application/json" -H "Cache-Control: no-cache" "http://localhost:3001/login"

You should get the message: All good. You DO NOT need to be authenticated to call /login.

To test secure endpoints, send a GET request to http://localhost:3001/photos. In this case, you must add a valid access token as an Authorization header to your request.

curl -X GET -H "Authorization: Bearer {YOUR_ACCESS_TOKEN}" -H "Cache-Control: no-cache" "http://localhost:3001/photos"

You should get the message: All good. You can see this because you are Authenticated with a Token granted the 'read:photos' scope.

You can try with other HTTP methods and check if the scopes are validated as well.

If the token is not specified, you will get the following JSON as a response:

{
  "timestamp": 1488492258708,
  "status": 401,
  "error": "Unauthorized",
  "message": "Unauthorized",
  "path": "/photos"
}

To obtain an access token, call the /oauth/token endpoint of the Auth0 Authentication API with Curl:

curl --request POST \
  --url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
  --header 'content-type: application/json' \
  --data '{"grant_type":"password", "username":"USERNAME_OR_EMAIL", "password":"PASSWORD", "audience":"{YOUR_API_IDENTIFIER}", "scope":"read:photos update:photos create:photos", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET"
 }'

In the example above, the delete:photos scope is not requested, so if you try to call DELETE /photos with an access token, the request will fail.

The domain, client ID and client secret values must match your Auth0 client. Check the values in the dashboard. Use the username and password of the user you want to authenticate with. Request the API audience with the API identifier and customize the scope to your needs.

Pass the access token in the Authorization header as a Bearer token.

Use Auth0 for FREECreate free Account