spring logo
java logo

Role-Based Access Control in Spring Boot

Updated on April 17, 2024
Photo of Matt Raible
Matt RaibleDeveloper Advocate

Introduction

Learning GoalLearn how to build a Spring Boot app that uses Role-Based Access Control (RBAC) for authorization.

In this guide, you will learn:

  • How to build a Spring Boot app with Java.
  • How to secure your app with OAuth and OpenID Connect.
  • How to use Auth0 Actions to convert Auth0 roles to Spring Security authorities.
  • How to secure methods with Spring Security's @PreAuthorize.

Why Spring Boot?

Spring Boot is one of the most popular frameworks for developing Java applications. It's used by companies around the world to simplify development and ease testing. If you want to be employed for years to come, Java is a good language to learn. Put those two together, and you have a winning combination!

The OAuth 2.0 authorization framework is a protocol that allows a user to grant a third-party website or application access to the user's protected resources without necessarily revealing their long-term credentials or even their identity.

OpenID Connect (OIDC) is an identity layer built on top of the OAuth 2.0 framework. It allows third-party applications to verify the identity of the end-user and to obtain basic user profile information.

Role-Based Access Control refers to the idea of assigning permissions to users based on their role within an organization. It offers a simple, manageable approach to access management that is less prone to error than assigning permissions to users individually.

In this guide, you'll learn how to use Java and Spring Boot to build a simple app that's secured with Spring Security and its OAuth support. You'll also learn how to convert your Auth0 roles to Spring Security authorities.

Set up a Development Environment

  • Use your favorite text editor or IDE. We recommend using IntelliJ IDEA.
  • Ensure that you have Java 17+ installed in your system. You can easily install it using SDKMAN!.
  • Windows commands in this guide are written for PowerShell.

Create an Auth0 Account

If you already have an Auth0 account, you can log in to your tenant and continue to the next step.

Otherwise, sign up for a free Auth0 account.

During the sign-up process, you create something called an Auth0 Tenant, where you configure your use of Auth0.

Once you sign in, Auth0 takes you to the Auth0 Dashboard, where you can configure and manage Auth0 assets, such as applications, APIs, connections, and user profiles.

Set up the Auth0 CLI

If you are not familiar with the Auth0 CLI, you can follow the "Auth0 CLI Basics" lab to learn how to build, manage, and test your Auth0 integrations from the command line.

There are different ways to install the Auth0 CLI, depending on your operating system.

LOADING...

Create a Spring Boot App

Use your browser and start.spring.io to create a new Spring Boot project with Spring Web and Okta dependencies.

This guide is using Spring Boot version 3.2.4.

You can also create projects with the command line. To create a Gradle project, run the following command:

LOADING...

Run the following command if you prefer to create a Maven project instead:

LOADING...

The Okta Spring Boot starter is a thin wrapper around Spring Security's resource server, OpenID Connect (OIDC) login, and OAuth client support. It secures all endpoints by default.

Navigate to the spring-rbac directory:

COMMAND
cd spring-rbac

Then, run the app with the following command:

GRADLE
MAVEN
./gradlew bootRun

Open the http://localhost:8080 URL in your favorite browser. You'll be prompted to log in since the Okta Spring Boot starter secures all URLs by default. You won't be able to log in yet because you haven't configured OIDC yet.

Secure Spring Boot with OIDC

In a terminal, connect the Auth0 CLI to your Auth0 tenant.

COMMAND
auth0 login
Visit the Access Your Tenant section of the "Auth0 CLI Basics" lab to learn more about the auth0 login command.

Then, run the command below to create an OIDC application:

LOADING...

Copy the domain, client ID, and client secret of your app and paste it into the following input boxes:

When you enter a value in the input fields present on this page, any code snippet that uses such value updates to reflect it. Using the input fields makes copying and pasting code as you follow along easy.

For security, these configuration values are stored in memory and only used locally. They are gone as soon as you refresh the page!

Now, create an application.properties file in the root directory to configure the Okta Spring Boot starter:

application.properties
# trailing slash is important for issuer
okta.oauth2.issuer=https://AUTH0-DOMAIN/
okta.oauth2.client-id=AUTH0-CLIENT-ID
okta.oauth2.client-secret=AUTH0-CLIENT-SECRET

Add this file to .gitignore so you don't accidentally check it into source control:

.gitignore
application.properties

NOTE: You can also put these values in src/main/resources/application.properties. However, we recommend you DO NOT include the client secret in this file for security reasons.

Create a HomeController.java class next to DemoApplication.java:

LOADING...

Populate it with the following code:

src/main/java/com/example/demo/HomeController.java
package com.example.demo;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
class HomeController {
@GetMapping("/")
public String home(@AuthenticationPrincipal OidcUser user) {
return "Hello, " + user.getFullName() + "!";
}
}

This controller is protected by Spring Security because the Okta Spring Boot starter auto-configures everything to be protected by default.

Stop and restart the app:

GRADLE
MAVEN
./gradlew bootRun

Open a browser and navigate to http://localhost:8080. Log in with your Auth0 credentials or sign up as a new user and you should see your name displayed. If you don't have a user in your tenant yet, you can sign up with Google or create a new user with the Auth0 CLI:

COMMAND
auth0 users create

Use a Login Action to Add Roles

To add a new Administrator role, use the Auth0 CLI:

COMMAND
auth0 roles create --name Administrator --description "Administrators"

Find your user ID with auth0 users search and enter the full email address you used to log in previously.

Assign the role you just created to your user. You must use quotes around the user-id in the command below.

COMMAND
auth0 users roles assign "<user-id>"

Create a Login Action:

COMMAND
auth0 actions create --name "Add Roles" --trigger post-login
You can change the text editor used for editing templates, rules, and actions. Set the environment variable EDITOR to your preferred editor. For example export EDITOR="nano"

When the editor opens, use the following code in the onExecutePostLogin() function. This will set a https://spring-boot.example.com/roles claim in both the ID and access token.

ACTION
exports.onExecutePostLogin = async (event, api) => {
const namespace = "https://spring-boot.example.com";
if (event.authorization) {
api.idToken.setCustomClaim("preferred_username", event.user.email);
api.idToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
api.accessToken.setCustomClaim(
`${namespace}/roles`,
event.authorization.roles
);
}
};

Save the file using your editor. List the available actions with the following command:

COMMAND
auth0 actions list

Save your action ID into an environment variable and deploy the action you just created:

LOADING...

Once the action is deployed, you must attach it to the login flow. You can do this with Auth0 Management API for Actions:

LOADING...

Update application.properties to use the claim name that you defined in your action.

application.properties
okta.oauth2.groupsClaim=https://spring-boot.example.com/roles

Update your HomeController.java class to add Spring Security authorities to the response:

src/main/java/com/example/demo/HomeController.java
package com.example.demo;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.stream.Collectors;
@RestController
class HomeController {
@GetMapping("/")
public String home(@AuthenticationPrincipal OidcUser user) {
var authentication = SecurityContextHolder.getContext().getAuthentication();
var authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
return "Hello, " + user.getFullName() + "!<br/><br/>Authorities: " + authorities;
}
}

Restart your Spring Boot app and log in again. You should now see Spring Security authorities for your user.

Secure Methods with @PreAuthorize

Now that you have Spring Security authorities mapped from Auth0 roles, you can use Spring Security's @PreAuthorize annotation to secure methods. But first, you have to enable method-level security. Create a SecurityConfiguration.java class.

LOADING...

Add the following code with @EnableMethodSecurity annotation.

src/main/java/com/example/demo/SecurityConfiguration.java
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
@EnableMethodSecurity
public class SecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2Login(withDefaults())
.oauth2ResourceServer(jwt -> jwt.jwt(withDefaults()));
return http.build();
}
}

Add a couple of new methods to HomeController that are secured by authority and scope.

src/main/java/com/example/demo/HomeController.java
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import java.util.Map;
...
@GetMapping("/admin")
@PreAuthorize("hasAuthority('Administrator')")
public String admin(@AuthenticationPrincipal OidcUser user) {
return "Hello, Admin!<br/><br/><img src=" + user.getPicture() + " width=200/>";
}
@GetMapping("/profile")
@PreAuthorize("hasAuthority('SCOPE_profile')")
public Map<String, Object> profile(OAuth2AuthenticationToken authentication) {
return authentication.getPrincipal().getAttributes();
}

The admin() method requires you to be authenticated and have an Administrator role. The profile() method is secured with @PreAuthorize("hasAuthority('SCOPE_profile')") annotation to ensure that the /profile route cannot be accessed until you have authenticated with the profile scope. The Okta Spring Boot starter sends openid, email, profile scopes by default.

Restart your app, log in with the user to whom you assigned the 'Administrator' role, and confirm you can access http://localhost:8080/admin and http://localhost:8080/profile successfully.

This example proves that your Auth0 roles have been converted to Spring Security authorities, and included in your ID token.

Verify Roles Are in Your Access Token

To prove that roles have been added to your access token, create a new access token with the Auth0 CLI:

COMMAND
auth0 test token -a https://AUTH0-DOMAIN/api/v2/ -s openid

Select any available client when prompted. You will be prompted to open a browser window and log in with a user credential.

If you'd like to see what's in the access token you created, you can copy and paste it into JWT.io or use JWT UI.

You can also get an access token using the Authorization Code Flow.

Paste the access token value in the following field so that you can use it to test your application:

Update your application.properties file to use the same audience:

application.properties
okta.oauth2.audience=${okta.oauth2.issuer}api/v2/

Restart your Spring Boot app so the audience matches the access token.

Then, use it to access your /admin endpoint:

LOADING...

This will not work because the admin() method expects an OidcUser. However, when you access the /admin endpoint with an access token, Spring Security expects a JWT. Add a new method that will work with an access token.

src/main/java/com/example/demo/HomeController.java
import org.springframework.security.oauth2.jwt.Jwt;
...
@GetMapping("/jwt")
@PreAuthorize("hasAuthority('Administrator')")
public String jwt(@AuthenticationPrincipal Jwt jwt) {
return String.format("Hello, %s!\nClaims: %s",
jwt.getSubject(), jwt.getClaims());
}

Restart and you can now access the /jwt endpoint:

LOADING...

If you try to access the /profile endpoint, it won't work:

LOADING...

This is because your access token wasn't created with the profile scope. Create a new access with this scope:

COMMAND
auth0 test token -a https://AUTH0-DOMAIN/api/v2/ -s openid,profile

Paste the access token value in the following field so that you can use it to test your application:

Try again with the updated access token:

LOADING...

Now you'll experience a similar issue as before:

Create a new profileJwt() method in HomeController that will work with an access token:

src/main/java/com/example/demo/HomeController.java
@GetMapping("/profile-jwt")
@PreAuthorize("hasAuthority('SCOPE_profile')")
public Map<String, Object> profileJwt(@AuthenticationPrincipal Jwt jwt) {
return jwt.getClaims();
}

Restart your Spring Boot app, and try this new endpoint:

LOADING...

You will see the access token's claims in your terminal. Give yourself a pat on the back when it works!

Stop your Spring Boot app using Ctrl+C.

Recap

In this guide, you learned how to build a Spring Boot app with Java, secure it with Spring Security OAuth, and add Auth0 roles so they're converted to Spring Security authorities. It's pretty sweet how you can create and configure a Spring Boot app with Auth0 so fast!

curl -G https://start.spring.io/starter.tgz -d dependencies=web,okta -d baseDir=spring-rbac | tar -xzvf -
auth0 apps create \
--name "Spring Boot" \
--description "Spring Boot Example" \
--type regular \
--callbacks http://localhost:8080/login/oauth2/code/okta \
--logout-urls http://localhost:8080 \
--reveal-secrets

Check out our other Spring Boot guides Authentication in Spring Boot and Authorization in Spring Boot to learn more about Auth0 security integration in Spring Boot Java applications.

Be sure to visit the Okta Spring Boot Starter's GitHub repository to stay informed on the latest developments and join the growing community of Spring Boot users who use Okta.