Spring Boot API: Authorization
This tutorial demonstrates how to add authorization to an API using Spring Security 5. We recommend that you log in to follow this quickstart with examples configured for your account.
I want to integrate with my app
15 minutesI want to explore a sample app
2 minutesGet a sample configured with your account settings or check it out on Github.
This example demonstrates:
-
How to check for a JSON Web Token (JWT) in the
Authorization
header of an incoming HTTP request. -
How to check if the token is valid, using the JSON Web Key Set (JWKS) for your Auth0 account. To learn more about validating Access Tokens, see Validate Access Tokens.
Configure Auth0 APIs
Create an API
In the APIs section of the Auth0 dashboard, click Create API. Provide a name and an identifier for your API, for example, https://quickstarts/api
. You will use the identifier as an audience
later, when you are configuring the Access Token verification. Leave the Signing Algorithm as RS256.
By default, your API uses RS256 as the algorithm for signing tokens. Since RS256 uses a private/public keypair, it verifies the tokens against the public key for your Auth0 account. The public key is in the JSON Web Key Set (JWKS) format, and can be accessed here.
Define permissions
Permissions let you define how resources can be accessed on behalf of the user with a given access token. For example, you might choose to grant read access to the messages
resource if users have the manager access level, and a write access to that resource if they have the administrator access level.
You can define allowed permissions in the Permissions view of the Auth0 Dashboard's APIs section.
Configure the Sample Project
The sample project uses a /src/main/resources/application.yml
file, which configures it to use the correct Auth0 Domain and API Identifier for your API. If you download the code from this page it will be automatically configured. If you clone the example from GitHub, you will need to fill it in yourself.
auth0:
audience: {yourApiIdentifier}
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://{yourDomain}/
Was this helpful?
Attribute | Description |
---|---|
auth0.audience |
The unique identifier for your API. If you are following the steps in this tutorial it would be https://quickstarts/api . |
spring.security.oauth2.resourceserver.jwt.issuer-uri |
The issuer URI of the resource server, which will be the value of the iss claim in the JWT issued by Auth0. Spring Security will use this property to discover the authorization server's public keys and validate the JWT signature. The value will be your Auth0 domain with an https:// prefix and a / suffix (the trailing slash is important). |
Validate Access Tokens
Install dependencies
If you are using Gradle, you can add the required dependencies using the Spring Boot Gradle Plugin and the Dependency Management Plugin to resolve dependency versions:
// build.gradle
plugins {
id 'org.springframework.boot' version '2.5.12'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
}
Was this helpful?
If you are using Maven, add the Spring dependencies to your pom.xml
file:
// pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.12</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
</dependencies>
Was this helpful?
Configure the resource server
To configure the application as a Resource Server and validate the JWTs, create a class that will provide an instance of SecurityFilterChain
, and add the @EnableWebSecurity
annotation:
// src/main/java/com/auth0/example/security/SecurityConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.oauth2Login();
return http.build();
}
}
Was this helpful?
Validate the audience
Note: If you are using Spring Boot version 2.7 or higher, audience validation is supported out of the box by Spring Security. Instead of customizing beans as indicated below, you should just include the Auth0 API identifier as a value in the
spring.security.oauth2.resourceserver.jwt.audiences
array. Example:spring.security.oauth2.resourceserver.jwt.audiences=http://api-identifier
In addition to validating the JWT, you also need to validate that the JWT is intended for your API by checking the aud
claim of the JWT. Create a new class named AudienceValidator
that implements the OAuth2TokenValidator
interface:
// src/main/java/com/auth0/example/security/AudienceValidator.java
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
import org.springframework.security.oauth2.jwt.Jwt;
class AudienceValidator implements OAuth2TokenValidator<Jwt> {
private final String audience;
AudienceValidator(String audience) {
this.audience = audience;
}
public OAuth2TokenValidatorResult validate(Jwt jwt) {
OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);
if (jwt.getAudience().contains(audience)) {
return OAuth2TokenValidatorResult.success();
}
return OAuth2TokenValidatorResult.failure(error);
}
}
Was this helpful?
Update the SecurityConfig
class to configure a JwtDecoder
bean that uses the AudienceValidator
:
// src/main/java/com/auth0/example/security/SecurityConfig.java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoders;
import org.springframework.security.oauth2.jwt.JwtValidators;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
@EnableWebSecurity
public class SecurityConfig {
@Value("${auth0.audience}")
private String audience;
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
JwtDecoders.fromOidcIssuerLocation(issuer);
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);
jwtDecoder.setJwtValidator(withAudience);
return jwtDecoder;
}
}
Was this helpful?
Protect API Endpoints
The routes shown below are available for the following requests:
GET /api/public
: available for non-authenticated requestsGET /api/private
: available for authenticated requests containing an access token with no additional scopesGET /api/private-scoped
: available for authenticated requests containing an access token with theread:messages
scope granted
The example below shows how to secure API methods using the HttpSecurity
object provided in the filterChain()
method of the SecurityConfig
class. Route matchers are used to restrict access based on the level of authorization required:
// src/main/java/com/auth0/example/security/SecurityConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers("/api/public").permitAll()
.mvcMatchers("/api/private").authenticated()
.mvcMatchers("/api/private-scoped").hasAuthority("SCOPE_read:messages")
.and().cors()
.and().oauth2ResourceServer().jwt();
return http.build();
}
}
Was this helpful?
Create the API controller
Create a new class named Message
, which is the domain object the API will return:
// src/main/java/com/auth0/example/model/Message.java
public class Message {
private final String message;
public Message(String message) {
this.message = message;
}
public String getMessage() {
return this.message;
}
}
Was this helpful?
Create a new class named APIController
to handle requests to the endpoints:
// src/main/java/com/auth0/example/web/APIController.java
import com.auth0.example.model.Message;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(path = "api", produces = MediaType.APPLICATION_JSON_VALUE)
// For simplicity of this sample, allow all origins. Real applications should configure CORS for their use case.
@CrossOrigin(origins = "*")
public class APIController {
@GetMapping(value = "/public")
public Message publicEndpoint() {
return new Message("All good. You DO NOT need to be authenticated to call /api/public.");
}
@GetMapping(value = "/private")
public Message privateEndpoint() {
return new Message("All good. You can see this because you are Authenticated.");
}
@GetMapping(value = "/private-scoped")
public Message privateScopedEndpoint() {
return new Message("All good. You can see this because you are Authenticated with a Token granted the 'read:messages' scope");
}
}
Was this helpful?
Run the Application
To build and run the sample project, execute the bootRun
Gradle task.
Linux or macOS:
./gradlew bootRun
Was this helpful?
Windows:
gradlew.bat bootRun
Was this helpful?
If you are configuring your own application using Maven and the Spring Boot Maven Plugin, you can execute the spring-boot:run
goal.
Linux or macOS:
mvn spring-boot:run
Was this helpful?
Windows:
mvn.cmd spring-boot:run
Was this helpful?
The sample application will be available at http://localhost:3010/
. Read about how to test and use your API in the Using Your API article.