# FusionAuth QuickStart for Spring Boot With Thymeleaf QuickStart integration of a Spring Boot web application using Thymeleaf with FusionAuth. > For the index of this section of the site, see [llms.txt](https://4002.18-224-161-104.sslip.io/docs/llms.txt)  In this QuickStart, you are going to build an application with Spring Boot and integrate it with FusionAuth. You'll be building it for [ChangeBank](https://www.youtube.com/watch?v=CXDxNCzUspM), a global leader in converting dollars into coins. It'll have areas reserved for users who have logged in as well as public facing sections.It uses Spring Boot web and Thymeleaf, and sets up an OAuth authorization code grant flow, allowing users to log in to the application. The Docker Compose file and source code for a complete application are available at [https://github.com/FusionAuth/fusionauth-quickstart-java-springboot-web](https://github.com/FusionAuth/fusionauth-quickstart-java-springboot-web). ## Prerequisites * [Java](https://www.oracle.com/java/technologies/downloads/): Java can be installed via a variety of methods. This app was built using Java 17. You can change which version to use by editing the project's `pom.xml` file. The code in this example should be compatible down to Java 8, though minor differences may occur. * [Docker](https://www.docker.com): The quickest way to stand up FusionAuth. Ensure you also have [docker compose](https://docs.docker.com/compose/) installed. * (Alternatively, you can [install FusionAuth manually](https://4002.18-224-161-104.sslip.io/docs/get-started/download-and-install/fusionauth-app.md)). The example repository already has a Spring Boot application set up that includes a Maven wrapper. You can find out more by viewing: * [Spring Initializr](https://start.spring.io/): The Spring Boot template generator webpage. * [Maven Wrapper](https://maven.apache.org/wrapper/): A self-contained version of the Maven build tool which will download the application dependencies and compile the source code. Note This example was made with Maven, Spring Boot version 2.7, and Java 17. If you use different options, the configuration and code may be different. ## General Architecture Here's a typical application login flow before FusionAuth: ```mermaid sequenceDiagram participant User participant App as Application User ->> App : View Homepage User ->> App : Click Login Link App ->> User : Show Login Form User ->> App : Fill Out and Submit Login Form App ->> App : Authenticates User App ->> User : Display User's Account or Other Info ``` Request flow during login before FusionAuth And here's the same application login flow after introducing FusionAuth: ```mermaid sequenceDiagram participant User participant App as Application participant FusionAuth User ->> App : View Homepage User ->> App : Click Login Link (to FusionAuth) User ->> FusionAuth : View Login Form FusionAuth ->> User : Show Login Form User ->> FusionAuth : Fill Out and Submit Login Form FusionAuth ->> FusionAuth : Authenticates User FusionAuth ->> User: Go to Redirect URI User ->> App: Request the Redirect URI App ->> FusionAuth : Is User Authenticated? FusionAuth ->> App : User is Authenticated App ->> User : Display User's Account or Other Info ``` Request flow during login after FusionAuth In general, you are introducing FusionAuth in order to normalize and consolidate user data. This helps make sure it is consistent and up-to-date as well as offloading your login security and functionality to FusionAuth. ## Getting Started Start with getting FusionAuth up and running and creating a Spring Boot application with Thymeleaf. ### Clone The Code First, grab the code from the repository and change into that directory. ```shell-session $ git clone https://github.com/FusionAuth/fusionauth-quickstart-java-springboot-web.git ``` ```shell-session $ cd fusionauth-quickstart-java-springboot-web ``` ### Run FusionAuth Via Docker You'll find a Docker Compose file (`docker-compose.yml`) and an environment variables configuration file (`.env`) in the root directory of the repo. Assuming you have Docker installed, you can stand up FusionAuth on your machine with the following. ```shell-session $ docker compose up -d ``` Here you are using a bootstrapping feature of FusionAuth called [Kickstart](https://4002.18-224-161-104.sslip.io/docs/get-started/download-and-install/development/kickstart.md). When FusionAuth comes up for the first time, it will look at the `kickstart/kickstart.json` file and configure FusionAuth to your specified state. Note If you ever want to reset the FusionAuth application, you need to delete the volumes created by Docker Compose by executing `docker compose down -v`, then re-run `docker compose up -d`. FusionAuth will be initially configured with these settings: * Your client Id is `e9fdb985-9173-4e01-9d73-ac2d60d1dc8e`. * Your client secret is `super-secret-secret-that-should-be-regenerated-for-production`. * Your example username is `richard@example.com` and the password is `password`. * Your admin username is `admin@example.com` and the password is `password`. * The base URL of FusionAuth is `http://localhost:9011/`. You can log in to the [FusionAuth admin UI](http://localhost:9011/admin) and look around if you want to, but with Docker and Kickstart, everything will already be configured correctly. Note If you want to see where the FusionAuth values came from, they can be found in the [FusionAuth app](http://localhost:9011/admin). The tenant Id is found on the Tenants page. To see the Client Id and Client Secret, go to the Applications page and click the `View` icon under the actions for the ChangeBank application. You'll find the Client Id and Client Secret values in the `OAuth configuration` section. Caution The `.env` file contains passwords. In a real application, always add this file to your `.gitignore` file and never commit secrets to version control. Caution The `.env` and `kickstart.json` files contain passwords. In a real application, always add these files to your `.gitignore` file and never commit secrets to version control. ### Create A Basic Spring Boot Application Next, you'll set up a basic Spring Boot project with a single app. While this guide builds a new Spring Boot project, you can use the same method to integrate your existing project with FusionAuth. Note If you simply want to run the application, there is a completed version in the `complete-application` directory. You can use the following commands to get it up and running if you do not want to create your own. ```shell-session $ cd complete-application && \ ./mvnw package && \ ./mvnw spring-boot:run ``` Then view the application at the following URL [http://localhost:8080](http://localhost:8080). #### Get The Template Go to the Spring Initializr site at [https://start.spring.io/](https://start.spring.io/) and download your own starter package. Choose the following options. * Project - `Mavern` * Language - `Java` * Spring Boot Version - `2.7.16` * Project Metadata * Group - `io.fusionauth.quickstart` * Artifact - `springweb` * Package Name - `io.fusionauth.quickstart.springweb` * Packaging - `Jar` * Java Version - `17` This project has the following three dependencies which you will need to add by clicking the Add Dependencies button and searching for each dependency, when creating the package on the Initializr site. * OAuth2 Client * Thymeleaf * Spring Web If you choose different options, the configuration and code may be different. After entering the configuration settings above and adding the dependencies you can click the Generate button to download your starter package. You can unzip the package in any directory of your choice. This guide assumes you are in `your-application` directory. Note All the commands that follow presume you are running the command from the `your-application` root project directory ```shell-session $ mv ~/Downloads/springweb.zip . && \ unzip springweb.zip && \ cp -R springweb/. . && \ rm -rf springweb springweb.zip ``` The commands above will unzip your downloaded starter package and copy the package files into your current working directory. Remember to replace `~/Downloads/` in the command above with the actual path to your downloads folder. #### Install Dependencies And Build The Application From the `your-application` directory, run the following to execute the Maven build tool to download dependencies and build your application. ```shell-session $ ./mvnw package ``` Note If you are on Windows substitute `./mvnw` with `.\mvnw.cmd`. ## Authentication In this section, you'll build the integration with FusionAuth, which will allow users to log in to your application. ### Project Settings Open the `src/main/resources/application.properties` file and add the following configuration settings. ```plaintext spring.thymeleaf.cache=false spring.thymeleaf.enabled=true spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html spring.application.name=FusionAuth Spring Example spring.security.oauth2.client.registration.fusionauth-client.client-id=e9fdb985-9173-4e01-9d73-ac2d60d1dc8e spring.security.oauth2.client.registration.fusionauth-client.client-secret=super-secret-secret-that-should-be-regenerated-for-production spring.security.oauth2.client.registration.fusionauth-client.scope=email,openid,profile spring.security.oauth2.client.registration.fusionauth-client.redirect-uri=http://localhost:8080/login/oauth2/code/fusionauth spring.security.oauth2.client.registration.fusionauth-client.client-name=fusionauth spring.security.oauth2.client.registration.fusionauth-client.provider=fusionauth spring.security.oauth2.client.registration.fusionauth-client.client-authentication-method=basic spring.security.oauth2.client.registration.fusionauth-client.authorization-grant-type=authorization_code spring.security.oauth2.client.provider.fusionauth.authorization-uri=http://localhost:9011/oauth2/authorize spring.security.oauth2.client.provider.fusionauth.token-uri=http://localhost:9011/oauth2/token spring.security.oauth2.client.provider.fusionauth.user-info-uri=http://localhost:9011/oauth2/userinfo?schema=openid spring.security.oauth2.client.provider.fusionauth.user-name-attribute=name spring.security.oauth2.client.provider.fusionauth.user-info-authentication-method=header spring.security.oauth2.client.provider.fusionauth.jwk-set-uri=http://localhost:9011/.well-known/jwks.json ``` The properties with the `spring.thymeleaf` prefix enable Thymeleaf for server-side template rendering and define the location and suffix of the template files. The `spring.application.name` property defines the app name, which will show in your application view. The properties with the `spring.security.oauth2.client.registration` prefix configure the settings for the OAuth2 Client. The `client-id`, `client-secret`, `redirect-uri`, and `authorization-grant-type` values all need to match what is configured in FusionAuth. Because you used the Kickstart method, these settings should be correct, but if they are not, you can log in to [FusionAuth admin UI](http://localhost:9011/admin) and check the [OAuth Settings](https://4002.18-224-161-104.sslip.io/docs/get-started/core-concepts/types/applications.md#oauth) for your application. The properties with the `spring.security.oauth2.provider` prefix tell Spring where the important endpoints for FusionAuth are. ### Add Controllers In your starter package, the main class which is the entry point of the application is `SpringwebApplication.java` in `src/main/java/io/fusionauth/quickstart/springweb`. ```java package io.fusionauth.quickstart.springweb; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringwebApplication { public static void main(String[] args) { SpringApplication.run(SpringwebApplication.class, args); } } ``` Create a file named `HomeController.java` in the `src/main/java/io/fusionauth/quickstart/springweb` directory. To do so you can run the command below from `your-application` directory. ```shell-session $ touch src/main/java/io/fusionauth/quickstart/springweb/HomeController.java ``` Then copy the following code for the `HomeController` Java class into the file. ```java package io.fusionauth.quickstart.springweb; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HomeController { @Value("${spring.application.name}") String appName; @RequestMapping("/") public String homePage(Model model) { model.addAttribute("appName", appName); return "home"; } } ``` This controller serves the page for unauthenticated users on the index `/` route and shows the application name, which is injected from the `spring.application.name` property in the `application.properties` file. The `home` return string tells Spring to render the `home.html` template which you will create later. Create another file in the `src/main/java/io/fusionauth/quickstart/springweb` directory. This time, name it `AccountController.java`. ```shell-session $ touch src/main/java/io/fusionauth/quickstart/springweb/AccountController.java ``` Paste the following code into the `AccountController.java` file. ```java package io.fusionauth.quickstart.springweb; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class AccountController { @RequestMapping("/account") public String userPage(Model model, @AuthenticationPrincipal OidcUser principal) { if (principal != null) { model.addAttribute("profile", principal.getClaims()); } return "account"; } } ``` This controller serves the page for authenticated users on the `/account` route and adds the claims from the `OidcUser` returned from FusionAuth to the view model on the **profile** attribute. The `account` return string tells Spring to render the `account.html` template which you will create later. Next, create a file named `MakeChangeController.java` in the `src/main/java/io/fusionauth/quickstart/springweb` directory. ```shell-session $ touch src/main/java/io/fusionauth/quickstart/springweb/MakeChangeController.java ``` Then, copy the following code into the newly created file. ```java package io.fusionauth.quickstart.springweb; import io.fusionauth.quickstart.springweb.model.Change; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import java.math.BigDecimal; import java.math.RoundingMode; @Controller public class MakeChangeController { private static final Logger logger = LoggerFactory.getLogger(MakeChangeController.class); @GetMapping("/make-change") public String get(Model model, @AuthenticationPrincipal OidcUser principal) { model.addAttribute("change", new Change()); model.addAttribute("profile", principal.getClaims()); return "make-change"; } @PostMapping("/make-change") public String post(@ModelAttribute Change change, Model model, @AuthenticationPrincipal OidcUser principal) { model.addAttribute("profile", principal.getClaims()); change.setError(null); try { if (change.getTotal() != null) { BigDecimal totalValue = new BigDecimal(change.getTotal()); change.setNickels(totalValue .divide(new BigDecimal("0.05"), RoundingMode.HALF_DOWN) .intValue()); change.setPennies(totalValue .subtract(new BigDecimal("0.05") .multiply(new BigDecimal(change.getNickels()))) .multiply(new BigDecimal(100)) .intValue()); } } catch (Exception e) { logger.error(e.getMessage()); change.setError("Please enter a dollar amount."); } return "make-change"; } } ``` This controller serves both GET and POST requests on the `/make-change` route. Both methods add the claims to the **profile** attribute like `AccountController.java` does. `GetMapping` adds a new model object of `Change` to the view model. `PostMapping` takes the `Change` object as a parameter and uses the `total` to calculate how many nickels and pennies to return. If `total` is not a valid dollar (`BigDecimal`) value, it adds an error to the `Change` model object. The return string `make-change` tells Spring to render the `make-change.html` template which you will create later. ### Add The Model Object Now you'll create the model object referenced in the controllers. In the directory `src/main/java/io/fusionauth/quickstart/springweb`, create a new directory called `model`. ```shell-session $ mkdir src/main/java/io/fusionauth/quickstart/springweb/model ``` In the `model` directory, and create a new file named `Change.java`. ```shell-session $ touch src/main/java/io/fusionauth/quickstart/springweb/model/Change.java ``` Now, populate it with the follow code for the `Change` Java class. ```java package io.fusionauth.quickstart.springweb.model; public class Change { private String error; private String total = "0"; private Integer nickels = 0; private Integer pennies = 0; public String getError() { return error; } public void setError(String error) { this.error = error; } public String getTotal() { return total; } public void setTotal(String total) { this.total = total; } public Integer getNickels() { return nickels; } public void setNickels(Integer nickels) { this.nickels = nickels; } public Integer getPennies() { return pennies; } public void setPennies(Integer pennies) { this.pennies = pennies; } public String getMessage() { return String.format("We can make change for $%s with %s nickels and %s pennies!", getTotal(), getNickels(), getPennies()); } } ``` This model has four fields. * `error`: The error string if the input was invalid. * `total`: The total amount to divide into pennies and nickels. * `nickels`: The number of nickels returned from the `make change` operation. * `pennies`: The number of pennies returned from the `make change` operation. The model also has a `getMessage` method, which formats a message string to render on the template. ### Add View Templates Now you can add three views for Thymeleaf to render on the routes you defined: * `Home`: The welcome page an unauthenticated user will see when they visit your application. * `Account`: A protected view the user will see after they log in. * `Make Change`: A protected view to demonstrate making an authenticated form post to the backend. Create the template files in `src/main/resources/templates`. Create the `home.html` template file. ```shell-session $ touch src/main/resources/templates/home.html ``` Then paste the following code into it. ```html
To get started, log in or create a new account.