> ## Documentation Index
> Fetch the complete documentation index at: https://docs-staging-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Java Springboot API

> Add Auth0 JWT authentication to a Spring Boot API with protected endpoints

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

<HowToSchema />

<Callout icon="pencil" color="#FFC107" iconType="solid">
  This Quickstart is currently in **Beta**. We'd love to hear your feedback!
</Callout>

<Accordion title="Use AI to integrate Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).

  **Install:**

  ```bash theme={null}
  npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-springboot-api
  ```

  **Then ask your AI assistant:**

  ```text theme={null}
  Add Auth0 JWT authentication to my Spring Boot API
  ```

  Your AI assistant will automatically create your Auth0 API, fetch credentials, add the Auth0 Spring Boot API SDK dependency, configure `application.yml`, and implement a `SecurityFilterChain` with JWT validation and protected endpoints. [Full agent skills documentation →](/docs/quickstart/agent-skills)
</Accordion>

<Note>
  **Prerequisites:** Before you begin, ensure you have the following installed:

  * **[JDK 17+](https://openjdk.org/projects/jdk/17/)** for Spring Boot 3.2+ compatibility
  * **[Maven 3.6+](https://maven.apache.org/download.cgi)** or **[Gradle 7+](https://gradle.org/install/)** for dependency management
  * Your preferred IDE (IntelliJ IDEA, Eclipse, or VS Code with Java support)

  **Java Version Compatibility:** This quickstart works with **Java 17+** and **Spring Boot 3.2+**.
</Note>

## Get Started

This quickstart demonstrates how to add Auth0 JWT authentication to a Spring Boot API. You'll build a secure API with protected endpoints using the Auth0 Spring Boot API SDK.

<Steps>
  <Step title="Create a new project" stepNumber={1}>
    Create a new Spring Boot API project for this quickstart:

    **Using Spring Initializr:**

    ```bash theme={null}
    curl -L https://start.spring.io/starter.zip \
        -d dependencies=web,security \
        -d javaVersion=17 \
        -d name=auth0-api \
        -d artifactId=auth0-api \
        -d packageName=com.example.auth0api \
        -o auth0-api.zip

    mkdir auth0-api && unzip auth0-api.zip -d auth0-api && cd auth0-api
    ```

    **Or manually create with Maven:**

    ```bash theme={null}
    mvn archetype:generate \
        -DgroupId=com.example \
        -DartifactId=auth0-api \
        -DarchetypeArtifactId=maven-archetype-quickstart \
        -DinteractiveMode=false

    cd auth0-api
    ```
  </Step>

  <Step title="Add the Auth0 SDK" stepNumber={2}>
    Add the Auth0 Spring Boot API SDK to your project dependencies:

    **Maven (`pom.xml`):**

    ```xml theme={null}
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>auth0-springboot-api</artifactId>
        <version>1.0.0-beta.0</version>
    </dependency>
    ```

    **Gradle (`build.gradle`):**

    ```gradle theme={null}
    dependencies {
        implementation 'com.auth0:auth0-springboot-api:1.0.0-beta.0'
    }
    ```
  </Step>

  <Step title="Setup your Auth0 API" stepNumber={3}>
    Next up, you need to create a new API on your Auth0 tenant and add the configuration to your project.

    You can choose to do this 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 API and update your `application.yml` file:

        <Tabs>
          <Tab title="Mac/Linux">
            ```bash expandable theme={null}
            AUTH0_API_NAME="My Spring Boot API" && \
            AUTH0_API_IDENTIFIER="https://my-springboot-api" && \
            brew tap auth0/auth0-cli && \
            brew install auth0 && \
            auth0 login --no-input && \
            auth0 apis create -n "${AUTH0_API_NAME}" -i "${AUTH0_API_IDENTIFIER}" --offline-access --token-lifetime 86400 --signing-alg RS256 --json > auth0-api-details.json && \
            DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && \
            AUDIENCE=$(jq -r '.identifier' auth0-api-details.json) && \
            mkdir -p src/main/resources && \
            printf 'auth0:\n  domain: %s\n  audience: %s\n\nspring:\n  application:\n    name: auth0-api\n' "$DOMAIN" "$AUDIENCE" > src/main/resources/application.yml && \
            rm auth0-api-details.json && \
            echo "✅ application.yml created with your Auth0 API details:" && \
            cat src/main/resources/application.yml
            ```
          </Tab>

          <Tab title="Windows (PowerShell)">
            ```powershell expandable theme={null}
            $ApiName = "My Spring Boot API"
            $ApiIdentifier = "https://my-springboot-api"
            $latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/auth0/auth0-cli/releases/latest"
            $latestVersion = $latestRelease.tag_name
            $version = $latestVersion -replace "^v"
            Invoke-WebRequest -Uri "https://github.com/auth0/auth0-cli/releases/download/${latestVersion}/auth0-cli_${version}_Windows_x86_64.zip" -OutFile ".\auth0.zip"
            Expand-Archive ".\auth0.zip" .\
            [System.Environment]::SetEnvironmentVariable('PATH', $Env:PATH + ";${pwd}")
            auth0 login --no-input
            auth0 apis create -n "$ApiName" -i "$ApiIdentifier" --offline-access --token-lifetime 86400 --signing-alg RS256 --json | Set-Content -Path auth0-api-details.json
            $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name
            $Audience = (Get-Content -Raw auth0-api-details.json | ConvertFrom-Json).identifier
            New-Item -ItemType Directory -Force -Path "src\main\resources"
            @"
            auth0:
              domain: "$Domain"
              audience: "$Audience"

            spring:
              application:
                name: auth0-api
            "@ | Set-Content "src\main\resources\application.yml"
            Remove-Item auth0-api-details.json
            Write-Output "✅ application.yml created with your Auth0 API details:"
            Get-Content "src\main\resources\application.yml"
            ```
          </Tab>
        </Tabs>
      </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}
        auth0:
          domain: "YOUR_AUTH0_DOMAIN"
          audience: "YOUR_AUTH0_API_IDENTIFIER"

        spring:
          application:
            name: auth0-api
        ```

        1. Go to [Auth0 Dashboard](https://manage.auth0.com) → **Applications** → **APIs**
        2. Choose **Create API**
        3. Enter your API details:
           * **Name**: My Spring Boot API
           * **Identifier**: `https://my-springboot-api` (this becomes your Audience)
           * **Signing Algorithm**: RS256
        4. Choose **Create**
        5. Replace `YOUR_AUTH0_DOMAIN` in `application.yml` with your **Domain** from the Test tab (e.g., `your-tenant.auth0.com`)
        6. Replace `YOUR_AUTH0_API_IDENTIFIER` in `application.yml` with your **Identifier**. For example `https://my-springboot-api`.

        <Info>
          Your **Domain** should not include `https://`. Use only the domain and region. For example: `your-tenant.auth0.com`.

          The **Audience** (API Identifier) is a unique identifier for your API and can be any valid URI. It doesn't need to be a publicly accessible URL.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Configure authentication" stepNumber={4}>
    Create a security configuration class to enable Auth0 JWT authentication. Create `src/main/java/com/example/auth0api/SecurityConfig.java`:

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

    import com.auth0.spring.boot.Auth0AuthenticationFilter;
    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.config.http.SessionCreationPolicy;
    import org.springframework.security.web.SecurityFilterChain;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

    @Configuration
    public class SecurityConfig {

        @Bean
        SecurityFilterChain apiSecurity(HttpSecurity http, Auth0AuthenticationFilter authFilter) throws Exception {
            return http
                .csrf(csrf -> csrf.disable())
                .sessionManagement(session ->
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/api/public").permitAll()
                    .requestMatchers("/api/private").authenticated()
                    .anyRequest().permitAll())
                .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
        }
    }
    ```
  </Step>

  <Step title="Create public and protected endpoints" stepNumber={5}>
    Create API endpoints to test authentication. Create `src/main/java/com/example/auth0api/ApiController.java`:

    ```java src/main/java/com/example/auth0api/ApiController.java expandable theme={null}
    package com.example.auth0api;

    import com.auth0.spring.boot.Auth0AuthenticationToken;
    import org.springframework.http.ResponseEntity;
    import org.springframework.security.core.Authentication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;

    import java.util.Map;

    @RestController
    @RequestMapping("/api")
    public class ApiController {

        // Public endpoint - no authentication required
        @GetMapping("/public")
        public ResponseEntity<Map<String, String>> publicEndpoint() {
            return ResponseEntity.ok(Map.of(
                "message", "This endpoint is public - no authentication required"
            ));
        }

        // Protected endpoint - requires authentication
        @GetMapping("/private")
        public ResponseEntity<Map<String, Object>> privateEndpoint(Authentication authentication) {
            Auth0AuthenticationToken auth0Token = (Auth0AuthenticationToken) authentication;

            return ResponseEntity.ok(Map.of(
                "message", "This endpoint requires authentication",
                "user", authentication.getName(),
                "scopes", auth0Token.getAuthorities()
            ));
        }
    }
    ```
  </Step>

  <Step title="Run your API" stepNumber={6}>
    Start your Spring Boot application:

    **Maven:**

    ```bash theme={null}
    ./mvnw spring-boot:run
    ```

    **Gradle:**

    ```bash theme={null}
    ./gradlew bootRun
    ```

    Your API is now running on `http://localhost:8080` (check your console output for the exact URL).
  </Step>
</Steps>

<Check>
  **Checkpoint**

  You should now have a fully functional Auth0-protected API running on your [localhost](http://localhost:8080/)
</Check>

***

## Advanced Usage

<Accordion title="Calling Protected APIs">
  Test your protected endpoints with an access token.

  **1. Get an access token** from Auth0 using the Client Credentials flow:

  ```bash theme={null}
  curl --request POST \
    --url https://YOUR_DOMAIN/oauth/token \
    --header 'content-type: application/json' \
    --data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"YOUR_AUDIENCE","grant_type":"client_credentials"}'
  ```

  <Info>
    To get `YOUR_CLIENT_ID` and `YOUR_CLIENT_SECRET`, create a Machine to Machine
    Application in the [Auth0 Dashboard](https://manage.auth0.com/#/applications)
    and authorize it for your API.
  </Info>

  **2. Test the public endpoint** (should return 200 OK):

  ```bash theme={null}
  curl http://localhost:8080/api/public
  ```

  **3. Test the protected endpoint without authentication** (should return 401 Unauthorized):

  ```bash theme={null}
  curl http://localhost:8080/api/private
  ```

  **4. Call the protected endpoint with the token:**

  ```bash theme={null}
  curl http://localhost:8080/api/private \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```
</Accordion>

<Accordion title="Accessing JWT Claims">
  Access additional user information and token claims in your endpoints.

  ```java theme={null}
  @GetMapping("/profile")
  public ResponseEntity<Map<String, Object>> getUserProfile(Authentication authentication) {
      Auth0AuthenticationToken auth0Token = (Auth0AuthenticationToken) authentication;
      Map<String, Object> claims = auth0Token.getAuthenticationContext().getClaims();

      return ResponseEntity.ok(Map.of(
          "userId", authentication.getName(),
          "email", claims.get("email"),
          "scope", claims.get("scope"),
          "issuer", claims.get("iss"),
          "audience", claims.get("aud")
      ));
  }
  ```
</Accordion>

<Accordion title="Scope-Based Authorization">
  Implement fine-grained access control using JWT scopes for enhanced security.

  **1. Define scopes in your Auth0 API:**

  In the [Auth0 Dashboard](https://manage.auth0.com) → APIs → Your API → Permissions, add scopes:

  * `read:users` - Read user data
  * `write:users` - Write user data
  * `admin` - Administrative access

  **2. Configure authorization policies:**

  ```java theme={null}
  @Configuration
  public class SecurityConfig {
      @Bean
      SecurityFilterChain apiSecurity(HttpSecurity http, Auth0AuthenticationFilter authFilter) throws Exception {
          return http
              .csrf(csrf -> csrf.disable())
              .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
              .authorizeHttpRequests(auth -> auth
                  .requestMatchers("/api/admin/**").hasAuthority("SCOPE_admin")
                  .requestMatchers("/api/users/**").hasAnyAuthority("SCOPE_read:users", "SCOPE_write:users")
                  .requestMatchers("/api/private").authenticated()
                  .anyRequest().permitAll())
              .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
              .build();
      }
  }
  ```

  When requesting an access token, include the required scope:

  ```bash theme={null}
  curl --request POST \
    --url https://YOUR_DOMAIN/oauth/token \
    --header 'content-type: application/json' \
    --data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"YOUR_AUDIENCE","grant_type":"client_credentials","scope":"read:users write:users admin"}'
  ```
</Accordion>

<Accordion title="DPoP Enhanced Security">
  Enable DPoP (Demonstration of Proof-of-Possession) for enhanced token security that binds access tokens to cryptographic keys.

  **Configure DPoP support in application.yml:**

  ```yaml theme={null}
  auth0:
    domain: "your-tenant.auth0.com"
    audience: "https://my-springboot-api"
    dpopMode: ALLOWED # DISABLED, ALLOWED (default), REQUIRED
    dpopIatOffsetSeconds: 300 # 5 minutes (default)
    dpopIatLeewaySeconds: 60 # 1 minute leeway (default: 30s)
  ```

  **DPoP Modes:**

  * `ALLOWED` (default): Accepts both Bearer and DPoP tokens
  * `REQUIRED`: Only accepts DPoP tokens, rejects Bearer tokens
  * `DISABLED`: Standard JWT Bearer validation only

      <Info>
        Learn more about DPoP in the [Auth0 DPoP Documentation](https://auth0.com/docs/secure/sender-constraining/demonstrating-proof-of-possession-dpop).
      </Info>
</Accordion>

***

## Common Issues

<AccordionGroup>
  <Accordion title="401 Unauthorized - Invalid audience">
    **Problem:** API returns 401 even with valid tokens.

    **Solution:** Ensure `auth0.audience` exactly matches your Auth0 API identifier. The audience claim in the token must match this value.

    ```yaml theme={null}
    # ❌ WRONG
    auth0:
      audience: "my-api"

    # ✅ CORRECT
    auth0:
      audience: "https://my-springboot-api"
    ```
  </Accordion>

  <Accordion title="401 Unauthorized - Invalid issuer">
    **Problem:** Token issuer validation fails.

    **Solution:** Verify your Domain is correct and does not include `https://`. Use domain without `https://` prefix.

    ```yaml theme={null}
    # ❌ WRONG
    auth0:
      domain: "https://your-tenant.auth0.com"

    # ✅ CORRECT
    auth0:
      domain: "your-tenant.auth0.com"
    ```
  </Accordion>

  <Accordion title="Configuration values not found">
    **Problem:** Application fails to start with configuration errors.

    **Solution:** Verify `application.yml` structure and property names. Ensure the auth0 section contains Domain and Audience values.

    ```yaml theme={null}
    # ✅ CORRECT structure
    auth0:
      domain: "your-tenant.auth0.com"
      audience: "https://your-api-identifier"

    spring:
      application:
        name: auth0-api
    ```
  </Accordion>

  <Accordion title="Filter order issues">
    **Problem:** Authentication not working despite correct configuration.

    **Solution:** Ensure Auth0AuthenticationFilter is properly integrated with Spring Security chain. The filter must be added before UsernamePasswordAuthenticationFilter.

    ```java theme={null}
    // ✅ CORRECT filter order
    .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
    ```
  </Accordion>

  <Accordion title="Network connectivity issues">
    **Problem:** JWKS retrieval failures or connection timeouts.

    **Solution:** Corporate firewall may be blocking Auth0 endpoints. Whitelist Auth0 domains for HTTPS access:

    ```bash theme={null}
    # Required firewall rules (outbound HTTPS/443)
    *.auth0.com
    *.us.auth0.com  # For US region tenants
    *.eu.auth0.com  # For EU region tenants
    *.au.auth0.com  # For AU region tenants
    ```
  </Accordion>

  <Accordion title="Scopes not working in authorization policies">
    **Problem:** Scope-based authorization policies always fail.

    **Solution:** Ensure your access token includes the required scopes. When requesting a token, specify the scopes:

    ```bash theme={null}
    curl --request POST \
      --url https://YOUR_DOMAIN/oauth/token \
      --data '{"client_id":"...","client_secret":"...","audience":"...","grant_type":"client_credentials","scope":"read:users write:users admin"}'
    ```

    Also verify scopes are defined in your Auth0 API settings (Dashboard → APIs → Your API → Permissions).
  </Accordion>
</AccordionGroup>

***

## Additional Resources

<CardGroup cols={3}>
  <Card title="SDK Documentation" icon="book" href="https://github.com/auth0/auth0-auth-java/tree/main/auth0-springboot-api">
    Complete SDK documentation and API reference
  </Card>

  <Card title="Code Examples" icon="code" href="https://github.com/auth0/auth0-auth-java/blob/main/auth0-springboot-api/EXAMPLES.md">
    Comprehensive code examples and integration patterns
  </Card>

  <Card title="DPoP Documentation" icon="shield" href="https://auth0.com/docs/secure/sender-constraining/demonstrating-proof-of-possession-dpop">
    Learn about proof-of-possession security enhancement
  </Card>

  <Card title="Spring Security Reference" icon="book" href="https://docs.spring.io/spring-security/reference/">
    Official Spring Security documentation
  </Card>

  <Card title="Auth0 Dashboard" icon="settings" 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 all features is available in the SDK repository.

<Card title="Playground Application" icon="github" href="https://github.com/auth0/auth0-auth-java/tree/main/auth0-springboot-api-playground">
  Includes public and protected endpoints, DPoP support, and comprehensive
  examples
</Card>

Clone and run:

```bash theme={null}
git clone https://github.com/auth0/auth0-auth-java.git
cd auth0-auth-java/auth0-springboot-api-playground

# Update src/main/resources/application.yml with your Auth0 configuration
# Then run:
./mvnw spring-boot:run
```

**Testing with curl:**

```bash theme={null}
# Test public endpoint
curl http://localhost:8080/api/public

# Get access token (replace with your Auth0 credentials)
curl -X POST https://YOUR_DOMAIN/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "audience": "https://my-springboot-api",
    "grant_type": "client_credentials"
  }'

# Test protected endpoint with Bearer token
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
     http://localhost:8080/api/private
```
