> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Java Spring Boot

> Add Auth0 login to a Spring Boot web application using the Okta Spring Boot Starter.

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

<HowToSchema />

<Note>
  **Prerequisites:**

  * JDK 17+ ([download](https://adoptium.net/))
  * Maven 3.6+ or Gradle 7+ ([Maven](https://maven.apache.org/download.cgi) | [Gradle](https://gradle.org/install/))
  * An IDE (IntelliJ IDEA, Eclipse, or VS Code recommended)

  **Java Version Compatibility:** Spring Boot 3.x+ and the Okta Spring Boot Starter 3.x require Java 17 or higher.
</Note>

## Get Started

This quickstart demonstrates how to add Auth0 login to a Spring Boot web application. You'll build a secure web app with login, logout, and a protected profile page using the Okta Spring Boot Starter, which auto-configures Spring Security's OAuth2 login support.

<Steps>
  <Step title="Create a new project" stepNumber={1}>
    Generate a Spring Boot project with the required dependencies.

    <Tabs>
      <Tab title="Using Spring Initializr">
        ```bash theme={null}
        curl -L https://start.spring.io/starter.zip \
            -d dependencies=web,security,thymeleaf \
            -d javaVersion=17 \
            -d name=auth0-webapp \
            -d artifactId=auth0-webapp \
            -d packageName=com.auth0.example \
            -o auth0-webapp.zip

        mkdir auth0-webapp && unzip auth0-webapp.zip -d auth0-webapp && cd auth0-webapp
        ```
      </Tab>

      <Tab title="Or manually create with Maven">
        ```bash theme={null}
        mvn archetype:generate \
            -DgroupId=com.auth0 \
            -DartifactId=auth0-webapp \
            -DarchetypeArtifactId=maven-archetype-quickstart \
            -DinteractiveMode=false

        cd auth0-webapp
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add the Okta Spring Boot Starter" stepNumber={2}>
    Add the Okta Spring Boot Starter dependency to your project. This pulls in Spring Security OAuth2 login support with Auth0/Okta-specific auto-configuration.

    <Tabs>
      <Tab title="Maven (pom.xml)">
        ```xml theme={null}
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity6</artifactId>
        </dependency>
        <dependency>
            <groupId>com.okta.spring</groupId>
            <artifactId>okta-spring-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        ```
      </Tab>

      <Tab title="Gradle (build.gradle)">
        ```gradle theme={null}
        dependencies {
            implementation 'org.springframework.boot:spring-boot-starter-security'
            implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
            implementation 'org.springframework.boot:spring-boot-starter-web'
            implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
            implementation 'com.okta.spring:okta-spring-boot-starter:3.1.0'
            testImplementation 'org.springframework.boot:spring-boot-starter-test'
            testImplementation 'org.springframework.security:spring-security-test'
            testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
        }
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Configure Auth0" stepNumber={3}>
    Create a Regular Web Application in your Auth0 tenant and add the configuration to your project.

    You can choose to set up your Auth0 app automatically by running a CLI command, or do it manually via the Dashboard:

    <Tabs>
      <Tab title="CLI">
        Run the following shell command on your project's root directory to create an Auth0 application and update your `src/main/resources/application.yml`:

        <CodeGroup>
          ```shellscript Mac theme={null}
          # Install Auth0 CLI (if not already installed)
          brew tap auth0/auth0-cli && brew install auth0

          # Set up Auth0 app and generate application.yml
          auth0 qs setup --app --type regular --framework spring-boot --build-tool maven --port 3000 --name "My Spring Boot App"
          ```

          ```powershell Windows theme={null}
          # Install Auth0 CLI (if not already installed)
          scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
          scoop install auth0

          # Set up Auth0 app and generate application.yml
          auth0 qs setup --app --type regular --framework spring-boot --build-tool maven --port 3000 --name "My Spring Boot App"
          ```
        </CodeGroup>

        <Note>
          This command will:

          1. Check if you're authenticated (and prompt for login if needed)
          2. Create an Auth0 Regular Web Application configured for `http://localhost:3000`
          3. Generate `src/main/resources/application.yml` with `okta.oauth2.issuer`, `okta.oauth2.client-id`, and `okta.oauth2.client-secret`

          Gradle users should substitute `--build-tool gradle` for `--build-tool maven`.
        </Note>
      </Tab>

      <Tab title="Dashboard">
        Before you start, add Auth0 configuration to your `src/main/resources/application.yml` file:

        ```yaml src/main/resources/application.yml expandable theme={null}
        server:
          port: 3000

        okta:
          oauth2:
            issuer: "https://YOUR_AUTH0_DOMAIN/"
            client-id: "YOUR_CLIENT_ID"
            client-secret: "YOUR_CLIENT_SECRET"
        ```

        1. Go to [Auth0 Dashboard](https://manage.auth0.com) → **Applications** → **Applications**.
        2. Choose **Create Application**.
        3. Enter a name (e.g., "My Spring Boot Webapp") and select **Regular Web Applications**.
        4. Choose **Create**.
        5. Go to the **Application Settings** tab and configure:
           * **Allowed Callback URLs**: `http://localhost:3000/login/oauth2/code/okta`
           * **Allowed Logout URLs**: `http://localhost:3000/`
        6. Copy the **Domain**, **Client ID**, and **Client Secret** from the **Application Settings** tab.
        7. Replace the placeholder values in `application.yml`.

        <Info>
          The **Callback URL** must match exactly. Spring Security's OAuth2 login uses the path `/login/oauth2/code/okta` by default.

          The **Issuer** must include `https://` and a trailing `/`. Use only the domain and region. For example: `https://dev-abc123.us.auth0.com/`.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Configure authentication" stepNumber={4}>
    Create a security configuration that enables OAuth2 login and handles Auth0 logout. Unauthenticated users are redirected to the Auth0 login page automatically.

    ```java lines expandable theme={null}
    // src/main/java/com/auth0/example/SecurityConfig.java

    package com.auth0.example;

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.security.web.authentication.logout.LogoutHandler;
    import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

    import java.io.IOException;

    import static org.springframework.security.config.Customizer.withDefaults;

    @Configuration
    public class SecurityConfig {

        @Value("${okta.oauth2.issuer}")
        private String issuer;
        @Value("${okta.oauth2.client-id}")
        private String clientId;

        @Bean
        public SecurityFilterChain configure(HttpSecurity http) throws Exception {
            http
                .authorizeHttpRequests(authorize -> authorize
                    .requestMatchers("/", "/images/**").permitAll()
                    .anyRequest().authenticated()
                )
                .oauth2Login(withDefaults())
                .logout(logout -> logout
                    .addLogoutHandler(logoutHandler()));
            return http.build();
        }

        private LogoutHandler logoutHandler() {
            return (request, response, authentication) -> {
                try {
                    String baseUrl = ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
                    response.sendRedirect(issuer + "v2/logout?client_id=" + clientId + "&returnTo=" + baseUrl);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            };
        }
    }
    ```
  </Step>

  <Step title="Create controllers and views" stepNumber={5}>
    Create the controllers and the Thymeleaf templates for the home and profile pages.

    <AuthCodeGroup>
      ```java src/main/java/com/auth0/example/HomeController.java expandable lines theme={null}
      package com.auth0.example;

      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;

      @Controller
      public class HomeController {

          @GetMapping("/")
          public String home(Model model, @AuthenticationPrincipal OidcUser principal) {
              if (principal != null) {
                  model.addAttribute("profile", principal.getClaims());
              }
              return "index";
          }
      }
      ```

      ```java src/main/java/com/auth0/example/ProfileController.java expandable lines theme={null}
      package com.auth0.example;

      import com.fasterxml.jackson.core.JsonProcessingException;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
      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 java.util.Map;

      @Controller
      public class ProfileController {

          private final static ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());

          @GetMapping("/profile")
          public String profile(Model model, @AuthenticationPrincipal OidcUser oidcUser) {
              model.addAttribute("profile", oidcUser.getClaims());
              model.addAttribute("profileJson", claimsToJson(oidcUser.getClaims()));
              return "profile";
          }

          private String claimsToJson(Map<String, Object> claims) {
              try {
                  return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(claims);
              } catch (JsonProcessingException jpe) {
                  return "Error parsing claims to JSON.";
              }
          }
      }
      ```

      ```html src/main/resources/templates/index.html expandable lines theme={null}
      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
      <head>
          <meta charset="UTF-8">
          <title>Auth0 Spring Boot Login</title>
      </head>
      <body>
          <h1>Auth0 Spring Boot Login Sample</h1>

          <div sec:authorize="!isAuthenticated()">
              <p>You are not logged in.</p>
              <a href="/oauth2/authorization/okta">Login</a>
          </div>

          <div sec:authorize="isAuthenticated()">
              <p>Welcome, <span sec:authentication="name">User</span>!</p>
              <ul>
                  <li><a href="/profile">View Profile</a></li>
                  <li>
                      <form th:action="@{/logout}" method="post" style="display:inline;">
                          <button type="submit">Logout</button>
                      </form>
                  </li>
              </ul>
          </div>
      </body>
      </html>
      ```

      ```html src/main/resources/templates/profile.html expandable lines theme={null}
      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
          <meta charset="UTF-8">
          <title>User Profile</title>
      </head>
      <body>
          <h1>User Profile</h1>
          <a href="/">Home</a>

          <div th:if="${profile}">
              <img th:if="${profile['picture']}" th:src="${profile['picture']}" width="64" height="64" alt="Profile picture" />
              <h2 th:text="${profile['name']}">Name</h2>
              <p th:text="${profile['email']}">Email</p>
          </div>

          <h3>All Claims</h3>
          <pre th:text="${profileJson}">Claims JSON</pre>

          <form th:action="@{/logout}" method="post">
              <button type="submit">Logout</button>
          </form>
      </body>
      </html>
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Run your application" stepNumber={6}>
    Start the application using the Maven or Gradle wrapper.

    <Tabs>
      <Tab title="Maven">
        ```bash theme={null}
        ./mvnw spring-boot:run
        ```
      </Tab>

      <Tab title="Gradle">
        ```bash theme={null}
        ./gradlew bootRun
        ```
      </Tab>
    </Tabs>

    Your application is now running on `http://localhost:3000`. Navigate to `http://localhost:3000/profile` to trigger the Auth0 login flow.
  </Step>
</Steps>

<Check>
  You should now have a fully functional Spring Boot web application with Auth0 login running on your [localhost](http://localhost:3000/). The home page is public, and navigating to `/profile` redirects unauthenticated users to the Auth0 login page.
</Check>

***

## Advanced Usage

<Accordion title="Accessing User Profile Claims">
  The `@AuthenticationPrincipal OidcUser` parameter gives you access to all claims from the ID token. Use `getClaims()` to retrieve the full set or individual getter methods for specific claims.

  ```java theme={null}
  @GetMapping("/profile")
  public String profile(Model model, @AuthenticationPrincipal OidcUser oidcUser) {
      model.addAttribute("name", oidcUser.getFullName());
      model.addAttribute("email", oidcUser.getEmail());
      model.addAttribute("picture", oidcUser.getPicture());
      model.addAttribute("sub", oidcUser.getSubject());
      model.addAttribute("allClaims", oidcUser.getClaims());
      return "profile";
  }
  ```
</Accordion>

<Accordion title="Role-Based Access Control">
  You can restrict access to pages based on Auth0 roles. First, add roles to the ID token using an Auth0 Action, then use `hasAuthority()` in your security configuration.

  ### Add Roles to Tokens

  1. Go to [Auth0 Dashboard](https://manage.auth0.com) → **Actions** → **Flows** → **Login**.
  2. Create a custom Action that adds roles as a custom claim to the ID token:

  ```javascript theme={null}
  exports.onExecutePostLogin = async (event, api) => {
    const namespace = "https://my-app.example.com";
    if (event.authorization) {
      api.idToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
    }
  };
  ```

  ### Configure Authorization

  Update your `SecurityConfig` to require specific roles on endpoints:

  ```java expandable theme={null}
  @Bean
  public SecurityFilterChain configure(HttpSecurity http) throws Exception {
      http
          .authorizeHttpRequests(authorize -> authorize
              .requestMatchers("/", "/images/**").permitAll()
              .requestMatchers("/admin/**").hasAuthority("ROLE_admin")
              .anyRequest().authenticated()
          )
          .oauth2Login(withDefaults())
          .logout(logout -> logout
              .addLogoutHandler(logoutHandler()));
      return http.build();
  }
  ```
</Accordion>

<Accordion title="Custom Authority Mapping">
  The Okta starter supports custom authority mapping through the `AuthoritiesProvider` interface. Register a bean to add custom `GrantedAuthority` objects based on user attributes or external data sources.

  ```java expandable theme={null}
  package com.auth0.example;

  import com.okta.spring.boot.oauth.AuthoritiesProvider;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  import org.springframework.security.core.GrantedAuthority;
  import org.springframework.security.core.authority.SimpleGrantedAuthority;

  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;

  @Configuration
  public class AuthoritiesConfig {

      @Bean
      AuthoritiesProvider customAuthoritiesProvider() {
          return (user, userRequest) -> {
              Set<GrantedAuthority> authorities = new HashSet<>();

              // Map custom roles claim to Spring Security authorities
              Object roles = user.getAttribute("https://my-app.example.com/roles");
              if (roles instanceof List<?> roleList) {
                  roleList.forEach(role ->
                      authorities.add(new SimpleGrantedAuthority("ROLE_" + role))
                  );
              }

              return authorities;
          };
      }
  }
  ```
</Accordion>

***

## Common Issues

<AccordionGroup>
  <Accordion title="Redirect to login fails - Invalid callback URL">
    After selecting login, Auth0 shows an error about a callback URL mismatch.

    The **Allowed Callback URLs** in your Auth0 application must exactly match the callback URL used by Spring Security. The default is `http://localhost:3000/login/oauth2/code/okta`.

    1. Go to [Auth0 Dashboard](https://manage.auth0.com) → **Applications** → Your App → **Settings**.
    2. Under **Allowed Callback URLs**, add: `http://localhost:3000/login/oauth2/code/okta`.
    3. Choose **Save Changes**.
  </Accordion>

  <Accordion title="Invalid issuer at startup">
    The application fails to start or login fails with an issuer mismatch.

    The `okta.oauth2.issuer` must be the full Auth0 tenant URL including `https://` and a trailing `/`.

    ```yaml theme={null}
    # ❌ WRONG - missing https:// or trailing slash
    okta:
      oauth2:
        issuer: "dev-abc123.us.auth0.com"

    # ✅ CORRECT - full URL with trailing slash
    okta:
      oauth2:
        issuer: "https://dev-abc123.us.auth0.com/"
    ```
  </Accordion>

  <Accordion title="OIDC discovery failure at startup">
    The application fails to start with a connection error when fetching `/.well-known/openid-configuration`.

    The Okta Spring Boot Starter fetches the OpenID Connect discovery document from your issuer URL at startup. Verify that the issuer URL is correct and reachable from your network. If behind a corporate firewall, configure the proxy:

    ```yaml theme={null}
    okta:
      oauth2:
        issuer: "https://dev-abc123.us.auth0.com/"
        proxy:
          host: "proxy.example.com"
          port: 8080
    ```
  </Accordion>

  <Accordion title="Configuration values not found">
    The application starts but login fails because configuration properties are not being read.

    Ensure your `application.yml` uses the correct YAML indentation under the `okta.oauth2` namespace:

    ```yaml theme={null}
    # ❌ WRONG - flat structure, not nested
    okta.oauth2.issuer: "https://dev-abc123.us.auth0.com/"

    # ✅ CORRECT - properly nested YAML
    okta:
      oauth2:
        issuer: "https://dev-abc123.us.auth0.com/"
        client-id: "YOUR_CLIENT_ID"
        client-secret: "YOUR_CLIENT_SECRET"
    ```
  </Accordion>

  <Accordion title="Logout does not clear Auth0 session">
    After selecting logout, the user is immediately logged back in without seeing the Auth0 login page.

    Ensure your `SecurityConfig` includes the custom `LogoutHandler` that redirects to the Auth0 `/v2/logout` endpoint. Also verify that the **Allowed Logout URLs** in your Auth0 Application Settings includes `http://localhost:3000/`.
  </Accordion>
</AccordionGroup>

***

## Additional Resources

<CardGroup cols={3}>
  <Card title="SDK Documentation" icon="book" href="https://github.com/okta/okta-spring-boot">
    Complete SDK documentation, source code, and release notes
  </Card>

  <Card title="Auth0 Documentation" icon="file-lines" href="https://auth0.com/docs">
    Official Auth0 documentation for Spring Boot applications
  </Card>

  <Card title="Spring Security Reference" icon="shield" href="https://docs.spring.io/spring-security/reference/servlet/oauth2/login.html">
    Spring Security OAuth2 Login documentation
  </Card>

  <Card title="Configuration Reference" icon="gear" href="https://github.com/okta/okta-spring-boot#configuration-reference">
    All available okta.oauth2.\* configuration properties
  </Card>

  <Card title="Auth0 Dashboard" icon="browser" href="https://manage.auth0.com/">
    Manage your Auth0 APIs and applications
  </Card>

  <Card title="Community Forum" icon="comments" href="https://community.auth0.com/">
    Get help from the Auth0 community
  </Card>
</CardGroup>

***

## Sample Application

A complete sample application demonstrating login, profile display, and logout with Auth0 is available in the Auth0 samples repository.

<Card title="MVC Login Sample" icon="github" href="https://github.com/auth0-samples/auth0-spring-boot-login-samples/tree/master/mvc-login">
  Includes login, logout, and profile page with Auth0 OAuth2 integration
</Card>

Clone and run:

```bash theme={null}
git clone https://github.com/auth0-samples/auth0-spring-boot-login-samples.git
cd auth0-spring-boot-login-samples/mvc-login

# Update src/main/resources/application.yml with your Auth0 configuration
# Then run:
./gradlew bootRun
```

Open `http://localhost:3000` in your browser and select the **Login** link to test the Auth0 login flow.
