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

> Add Auth0 login, logout, and user profile to a Java EE 8 web application using the Security API

# Add Login to Your Java EE Application

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 />

<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-java-mvc-common
  ```

  **Then ask your AI assistant:**

  ```text theme={null}
  Add Auth0 authentication to my Java EE app
  ```

  Your AI assistant will automatically create your Auth0 application, fetch credentials, add the Auth0 Java MVC Commons SDK dependency, configure authentication with the Java EE 8 Security API, and implement login/logout flows. [Full agent skills documentation →](/docs/quickstart/agent-skills)
</Accordion>

<Note>
  **Prerequisites:**

  * [Java Development Kit (JDK)](https://www.oracle.com/java/technologies/downloads/) 11 or newer
  * [Apache Maven](https://maven.apache.org/download.cgi) 3.x
  * A Java EE 8 compatible application server (e.g., [WildFly](https://www.wildfly.org/) 14+, [Payara](https://www.payara.fish/) 5+, or [GlassFish](https://glassfish.org/) 5+)
  * An Auth0 account — [sign up for free](https://auth0.com/signup)
</Note>

## Get Started

Auth0 allows you to quickly add authentication and access user profile information in your application. This guide demonstrates how to integrate Auth0 with any new or existing Java EE application using the `auth0-java-mvc-common` SDK and the Java EE 8 Security API.

<Steps>
  <Step title="Create a new project" stepNumber={1}>
    Generate a new Maven WAR project:

    ```shellscript theme={null}
    mvn archetype:generate \
      -DgroupId=com.auth0.example \
      -DartifactId=java-ee-auth0-app \
      -DarchetypeArtifactId=maven-archetype-webapp \
      -DinteractiveMode=false
    ```

    Navigate into the project directory:

    ```shellscript theme={null}
    cd java-ee-auth0-app
    ```

    Create the Java source directories:

    ```shellscript theme={null}
    mkdir -p src/main/java/com/auth0/example/security
    mkdir -p src/main/java/com/auth0/example/web
    mkdir -p src/main/webapp/WEB-INF/jsp
    ```
  </Step>

  <Step title="Install the Auth0 SDK" stepNumber={2}>
    Replace the contents of your `pom.xml` with the following:

    ```xml pom.xml expandable lines theme={null}
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
             http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.auth0.example</groupId>
        <artifactId>java-ee-auth0-app</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>

        <properties>
            <maven.compiler.source>11</maven.compiler.source>
            <maven.compiler.target>11</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <failOnMissingWebXml>false</failOnMissingWebXml>
            <version.wildfly>23.0.2.Final</version.wildfly>
        </properties>

        <dependencies>
            <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>mvc-auth-commons</artifactId>
                <version>[1.0, 2.0)</version>
            </dependency>
            <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-api</artifactId>
                <version>8.0.1</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>javax.security.enterprise</groupId>
                <artifactId>javax.security.enterprise-api</artifactId>
                <version>1.0</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.16.0</version>
            </dependency>
        </dependencies>

        <build>
            <finalName>java-ee-auth0-app</finalName>
            <plugins>
                <plugin>
                    <groupId>org.wildfly.plugins</groupId>
                    <artifactId>wildfly-maven-plugin</artifactId>
                    <version>4.2.0.Final</version>
                    <configuration>
                        <version>${version.wildfly}</version>
                        <javaOpts>
                            <javaOpt>-Djboss.http.port=8080</javaOpt>
                        </javaOpts>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    ```

    The `javaee-api` and `javax.security.enterprise-api` dependencies are `provided` because the Java EE 8 application server supplies their implementations at runtime.
  </Step>

  <Step title="Setup your Auth0 Application" stepNumber={3}>
    <Tabs>
      <Tab title="Dashboard">
        1. Go to the [Auth0 Dashboard](https://manage.auth0.com/#/applications) and navigate to **Applications > Applications > Create Application**.
        2. Enter a name for your application (e.g., "My Java EE App").
        3. Select **Regular Web Applications** as the application type.
        4. Choose **Create**.
        5. Open the **Settings** tab.
        6. Note the **Domain**, **Client ID**, and **Client Secret** values.
        7. Scroll down to **Application URIs** and set:
           * **Allowed Callback URLs**: `http://localhost:8080/callback`
           * **Allowed Logout URLs**: `http://localhost:8080/`
        8. Choose **Save Changes**.
      </Tab>
    </Tabs>

    <Info>
      Make sure to [set up connections](https://auth0.com/docs/get-started/applications/set-up-database-connections) for your application so users can log in using their preferred identity provider.
    </Info>
  </Step>

  <Step title="Configure authentication" stepNumber={4}>
    Update your `web.xml` to store Auth0 configuration as JNDI environment entries. Replace the placeholder values with the **Domain**, **Client ID**, and **Client Secret** from your Auth0 Application Settings. Create a `jboss-web.xml` to configure the JASPIC security domain required by the Java EE 8 Security API, an `Auth0AuthenticationConfig.java` CDI bean to read the configuration from JNDI, and an `Auth0AuthenticationProvider.java` CDI producer to build the `AuthenticationController`.

    <Info>
      Do not include `https://` in your `auth0.domain` value. Use only the domain and region. For example: `dev-abc123.us.auth0.com`.
    </Info>

    <AuthCodeGroup>
      ```xml src/main/webapp/WEB-INF/web.xml expandable lines theme={null}
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
               http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
               version="3.1">

          <env-entry>
              <env-entry-name>auth0.domain</env-entry-name>
              <env-entry-type>java.lang.String</env-entry-type>
              <env-entry-value>YOUR_AUTH0_DOMAIN</env-entry-value>
          </env-entry>
          <env-entry>
              <env-entry-name>auth0.clientId</env-entry-name>
              <env-entry-type>java.lang.String</env-entry-type>
              <env-entry-value>YOUR_CLIENT_ID</env-entry-value>
          </env-entry>
          <env-entry>
              <env-entry-name>auth0.clientSecret</env-entry-name>
              <env-entry-type>java.lang.String</env-entry-type>
              <env-entry-value>YOUR_CLIENT_SECRET</env-entry-value>
          </env-entry>
          <env-entry>
              <env-entry-name>auth0.scope</env-entry-name>
              <env-entry-type>java.lang.String</env-entry-type>
              <env-entry-value>openid profile email</env-entry-value>
          </env-entry>
      </web-app>
      ```

      ```xml src/main/webapp/WEB-INF/jboss-web.xml lines theme={null}
      <?xml version="1.0"?>
      <jboss-web>
          <security-domain>jaspitest</security-domain>
          <context-root>/</context-root>
      </jboss-web>
      ```

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

      import javax.annotation.PostConstruct;
      import javax.enterprise.context.ApplicationScoped;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;

      @ApplicationScoped
      public class Auth0AuthenticationConfig {

          private String domain;
          private String clientId;
          private String clientSecret;
          private String scope;

          @PostConstruct
          public void init() {
              try {
                  Context env = (Context) new InitialContext().lookup("java:comp/env");
                  this.domain = (String) env.lookup("auth0.domain");
                  this.clientId = (String) env.lookup("auth0.clientId");
                  this.clientSecret = (String) env.lookup("auth0.clientSecret");
                  this.scope = (String) env.lookup("auth0.scope");
              } catch (NamingException ne) {
                  throw new IllegalArgumentException(
                          "Unable to lookup auth0 configuration properties from web.xml", ne);
              }

              if (this.domain == null || this.clientId == null
                      || this.clientSecret == null || this.scope == null) {
                  throw new IllegalArgumentException(
                          "domain, clientId, clientSecret, and scope must be set in web.xml");
              }
          }

          public String getDomain() { return domain; }
          public String getClientId() { return clientId; }
          public String getClientSecret() { return clientSecret; }
          public String getScope() { return scope; }
      }
      ```

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

      import com.auth0.AuthenticationController;
      import com.auth0.jwk.JwkProvider;
      import com.auth0.jwk.JwkProviderBuilder;

      import javax.enterprise.context.ApplicationScoped;
      import javax.enterprise.inject.Produces;

      @ApplicationScoped
      public class Auth0AuthenticationProvider {

          @Produces
          public AuthenticationController authenticationController(Auth0AuthenticationConfig config) {
              JwkProvider jwkProvider = new JwkProviderBuilder(config.getDomain()).build();
              return AuthenticationController.newBuilder(
                              config.getDomain(), config.getClientId(), config.getClientSecret())
                      .withJwkProvider(jwkProvider)
                      .build();
          }
      }
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Implement Java EE Security" stepNumber={5}>
    The Java EE 8 Security API uses `HttpAuthenticationMechanism` to handle authentication. You need to provide custom implementations of several security interfaces. The `@AutoApplySession` annotation enables the container to create a session for the authenticated user, so they remain logged in across requests.

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

      import com.auth0.jwt.interfaces.DecodedJWT;

      import javax.security.enterprise.CallerPrincipal;

      public class Auth0JwtPrincipal extends CallerPrincipal {

          private final DecodedJWT idToken;

          Auth0JwtPrincipal(DecodedJWT idToken) {
              super(idToken.getClaim("name").asString());
              this.idToken = idToken;
          }

          public DecodedJWT getIdToken() {
              return this.idToken;
          }
      }
      ```

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

      import com.auth0.jwt.JWT;
      import com.auth0.jwt.interfaces.DecodedJWT;

      import javax.security.enterprise.credential.Credential;

      class Auth0JwtCredential implements Credential {

          private Auth0JwtPrincipal auth0JwtPrincipal;

          Auth0JwtCredential(String token) {
              DecodedJWT decodedJWT = JWT.decode(token);
              this.auth0JwtPrincipal = new Auth0JwtPrincipal(decodedJWT);
          }

          Auth0JwtPrincipal getAuth0JwtPrincipal() {
              return auth0JwtPrincipal;
          }
      }
      ```

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

      import javax.enterprise.context.ApplicationScoped;
      import javax.security.enterprise.credential.Credential;
      import javax.security.enterprise.identitystore.CredentialValidationResult;
      import javax.security.enterprise.identitystore.IdentityStore;

      @ApplicationScoped
      public class Auth0JwtIdentityStore implements IdentityStore {

          @Override
          public CredentialValidationResult validate(final Credential credential) {
              CredentialValidationResult result = CredentialValidationResult.NOT_VALIDATED_RESULT;

              if (credential instanceof Auth0JwtCredential) {
                  Auth0JwtCredential auth0JwtCredential = (Auth0JwtCredential) credential;
                  result = new CredentialValidationResult(auth0JwtCredential.getAuth0JwtPrincipal());
              }

              return result;
          }
      }
      ```

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

      import com.auth0.AuthenticationController;
      import com.auth0.IdentityVerificationException;
      import com.auth0.Tokens;

      import javax.enterprise.context.ApplicationScoped;
      import javax.inject.Inject;
      import javax.security.enterprise.AuthenticationException;
      import javax.security.enterprise.AuthenticationStatus;
      import javax.security.enterprise.authentication.mechanism.http.AutoApplySession;
      import javax.security.enterprise.authentication.mechanism.http.HttpAuthenticationMechanism;
      import javax.security.enterprise.authentication.mechanism.http.HttpMessageContext;
      import javax.security.enterprise.identitystore.CredentialValidationResult;
      import javax.security.enterprise.identitystore.IdentityStoreHandler;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;

      @ApplicationScoped
      @AutoApplySession
      public class Auth0AuthenticationMechanism implements HttpAuthenticationMechanism {

          private final AuthenticationController authenticationController;
          private final IdentityStoreHandler identityStoreHandler;

          @Inject
          Auth0AuthenticationMechanism(AuthenticationController authenticationController,
                                       IdentityStoreHandler identityStoreHandler) {
              this.authenticationController = authenticationController;
              this.identityStoreHandler = identityStoreHandler;
          }

          @Override
          public AuthenticationStatus validateRequest(HttpServletRequest httpServletRequest,
                                                      HttpServletResponse httpServletResponse,
                                                      HttpMessageContext httpMessageContext)
                  throws AuthenticationException {

              if (isCallbackRequest(httpServletRequest)) {
                  try {
                      Tokens tokens = authenticationController.handle(
                              httpServletRequest, httpServletResponse);
                      Auth0JwtCredential auth0JwtCredential =
                              new Auth0JwtCredential(tokens.getIdToken());
                      CredentialValidationResult result =
                              identityStoreHandler.validate(auth0JwtCredential);
                      return httpMessageContext.notifyContainerAboutLogin(result);
                  } catch (IdentityVerificationException e) {
                      return httpMessageContext.responseUnauthorized();
                  }
              }

              return httpMessageContext.doNothing();
          }

          private boolean isCallbackRequest(HttpServletRequest request) {
              return request.getServletPath().equals("/callback")
                      && request.getParameter("code") != null;
          }
      }
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Add login and logout functionality" stepNumber={6}>
    Create the servlets for login, callback, and logout. The `LoginServlet` builds the Auth0 authorization URL and redirects the user. The `CallbackServlet` handles the redirect after authentication — the `Auth0AuthenticationMechanism` intercepts this request first to exchange the authorization code for tokens, so the servlet only needs to redirect. The `LogoutServlet` clears the session and redirects to the Auth0 logout endpoint.

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

      import com.auth0.AuthenticationController;
      import com.auth0.example.security.Auth0AuthenticationConfig;

      import javax.inject.Inject;
      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;

      @WebServlet(urlPatterns = "/login")
      public class LoginServlet extends HttpServlet {

          private final Auth0AuthenticationConfig config;
          private final AuthenticationController authenticationController;

          @Inject
          LoginServlet(Auth0AuthenticationConfig config,
                       AuthenticationController authenticationController) {
              this.config = config;
              this.authenticationController = authenticationController;
          }

          @Override
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                  throws ServletException, IOException {
              String callbackUrl = String.format(
                      "%s://%s:%s%s/callback",
                      request.getScheme(),
                      request.getServerName(),
                      request.getServerPort(),
                      request.getContextPath());

              String authURL = authenticationController
                      .buildAuthorizeUrl(request, response, callbackUrl)
                      .withScope(config.getScope())
                      .build();

              response.sendRedirect(authURL);
          }
      }
      ```

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

      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;

      @WebServlet(urlPatterns = {"/callback"})
      public class CallbackServlet extends HttpServlet {

          @Override
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                  throws IOException {
              response.sendRedirect(request.getContextPath() + "/");
          }
      }
      ```

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

      import com.auth0.example.security.Auth0AuthenticationConfig;

      import javax.inject.Inject;
      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.net.URLEncoder;

      @WebServlet(urlPatterns = "/logout")
      public class LogoutServlet extends HttpServlet {

          private final Auth0AuthenticationConfig config;

          @Inject
          LogoutServlet(Auth0AuthenticationConfig config) {
              this.config = config;
          }

          @Override
          protected void doGet(final HttpServletRequest request,
                               final HttpServletResponse response)
                  throws ServletException, IOException {
              if (request.getSession() != null) {
                  request.getSession().invalidate();
              }

              String returnUrl = String.format("%s://%s",
                      request.getScheme(), request.getServerName());
              int port = request.getServerPort();
              String scheme = request.getScheme();

              if (("http".equals(scheme) && port != 80)
                      || ("https".equals(scheme) && port != 443)) {
                  returnUrl += ":" + port;
              }

              returnUrl += request.getContextPath() + "/";

              String logoutUrl = String.format(
                      "https://%s/v2/logout?client_id=%s&returnTo=%s",
                      config.getDomain(),
                      config.getClientId(),
                      URLEncoder.encode(returnUrl, "UTF-8"));

              response.sendRedirect(logoutUrl);
          }
      }
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Create the user interface" stepNumber={7}>
    Create the servlets and JSP pages for the home and profile views. The `HomeServlet` checks for an authenticated principal and sets the profile claims on the request. The `ProfileServlet` displays the user's profile and JWT claims, or redirects to login if not authenticated.

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

      import com.auth0.example.security.Auth0JwtPrincipal;

      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.security.Principal;

      @WebServlet(urlPatterns = "")
      public class HomeServlet extends HttpServlet {

          @Override
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                  throws ServletException, IOException {
              Principal principal = request.getUserPrincipal();

              if (principal instanceof Auth0JwtPrincipal) {
                  Auth0JwtPrincipal auth0JwtPrincipal = (Auth0JwtPrincipal) principal;
                  request.setAttribute("profile", auth0JwtPrincipal.getIdToken().getClaims());
              }

              request.getRequestDispatcher("/WEB-INF/jsp/home.jsp").forward(request, response);
          }
      }
      ```

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

      import com.auth0.example.security.Auth0JwtPrincipal;
      import com.auth0.jwt.interfaces.DecodedJWT;
      import com.fasterxml.jackson.databind.ObjectMapper;

      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.io.IOException;
      import java.nio.charset.StandardCharsets;
      import java.security.Principal;
      import java.util.Base64;

      @WebServlet(urlPatterns = {"/profile"})
      public class ProfileServlet extends HttpServlet {

          @Override
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                  throws ServletException, IOException {
              Principal principal = request.getUserPrincipal();

              if (principal instanceof Auth0JwtPrincipal) {
                  Auth0JwtPrincipal auth0JwtPrincipal = (Auth0JwtPrincipal) principal;
                  request.setAttribute("profile", auth0JwtPrincipal.getIdToken().getClaims());

                  String profileJson;
                  try {
                      DecodedJWT idToken = auth0JwtPrincipal.getIdToken();
                      byte[] decodedBytes = Base64.getUrlDecoder().decode(idToken.getPayload());
                      String decoded = new String(decodedBytes, StandardCharsets.UTF_8);
                      ObjectMapper objectMapper = new ObjectMapper();
                      Object json = objectMapper.readValue(decoded, Object.class);
                      profileJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json);
                  } catch (IOException ioe) {
                      profileJson = "Error converting JWT claims to JSON";
                  }

                  request.setAttribute("profileJson", profileJson);
                  request.getRequestDispatcher("/WEB-INF/jsp/profile.jsp").forward(request, response);
              } else {
                  request.getSession().setAttribute("Referer", request.getRequestURI());
                  request.getRequestDispatcher("/login").forward(request, response);
              }
          }
      }
      ```

      ```html src/main/webapp/WEB-INF/jsp/home.jsp expandable lines theme={null}
      <%@ page contentType="text/html;charset=UTF-8" %>
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="UTF-8">
          <title>Java EE Auth0 App</title>
          <style>
              body { font-family: sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; }
              nav { display: flex; justify-content: flex-end; gap: 12px; margin-bottom: 40px; align-items: center; }
              nav a { text-decoration: none; padding: 8px 16px; border-radius: 4px; }
              .btn-login { background: #635dff; color: white; }
              .btn-logout { background: #e0e0e0; color: #333; }
              nav img { border-radius: 50%; width: 36px; height: 36px; }
          </style>
      </head>
      <body>
          <nav>
              <c:choose>
                  <c:when test="${not empty profile}">
                      <a href="${pageContext.request.contextPath}/profile">Profile</a>
                      <img src="${profile.get('picture').asString()}" alt="Profile picture"/>
                      <a href="${pageContext.request.contextPath}/logout" class="btn-logout">Logout</a>
                  </c:when>
                  <c:otherwise>
                      <a href="${pageContext.request.contextPath}/login" class="btn-login">Login</a>
                  </c:otherwise>
              </c:choose>
          </nav>

          <h1>Java EE Sample Project</h1>
          <p>This is a sample application that demonstrates an authentication flow for a web application using Java EE.</p>
      </body>
      </html>
      ```

      ```html src/main/webapp/WEB-INF/jsp/profile.jsp expandable lines theme={null}
      <%@ page contentType="text/html;charset=UTF-8" %>
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="UTF-8">
          <title>Profile - Java EE Auth0 App</title>
          <style>
              body { font-family: sans-serif; max-width: 800px; margin: 40px auto; padding: 0 20px; }
              nav { display: flex; justify-content: flex-end; gap: 12px; margin-bottom: 40px; align-items: center; }
              nav a { text-decoration: none; padding: 8px 16px; border-radius: 4px; }
              .btn-logout { background: #e0e0e0; color: #333; }
              .profile-header { display: flex; align-items: center; gap: 20px; margin-bottom: 30px; }
              .profile-header img { border-radius: 50%; width: 80px; height: 80px; }
              .profile-header h2 { margin: 0 0 4px; }
              .profile-header p { margin: 0; color: #666; }
              pre { background: #f5f5f5; padding: 15px; border-radius: 5px; overflow-x: auto; }
          </style>
      </head>
      <body>
          <nav>
              <a href="${pageContext.request.contextPath}/">Home</a>
              <a href="${pageContext.request.contextPath}/logout" class="btn-logout">Logout</a>
          </nav>

          <div class="profile-header">
              <img src="${profile.get('picture').asString()}" alt="Profile picture"/>
              <div>
                  <h2>${profile.get('name').asString()}</h2>
                  <p>${profile.get('email').asString()}</p>
              </div>
          </div>

          <h3>Profile Details</h3>
          <pre><code>${profileJson}</code></pre>
      </body>
      </html>
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Run your application" stepNumber={8}>
    Build and run the application using the WildFly Maven plugin:

    ```shellscript theme={null}
    mvn clean wildfly:run
    ```

    Your application should start and display the URL it's listening on:

    ```
    INFO  [org.jboss.as] WFLYSRV0025: WildFly started
    ```

    Open your browser to [http://localhost:8080](http://localhost:8080). Click the **Login** link in the navigation bar. You will be redirected to the Auth0 login page. After authenticating, you will be redirected to the [profile page](http://localhost:8080/profile) where your user information and JWT claims are displayed.

    <Info>
      The sample uses JSP and is tested with the [WildFly](https://wildfly.org/) application server. You may need to adjust some steps if you are using a different Java EE 8 compatible container.
    </Info>
  </Step>
</Steps>

<Check>
  **Checkpoint**

  You should now have a fully functional Auth0-protected Java EE application running on [http://localhost:8080](http://localhost:8080). Users can log in, view their profile, and log out.
</Check>

***

## Advanced Usage

<Accordion title="Access User Profile Information">
  The `Auth0JwtPrincipal` is available via `request.getUserPrincipal()` in any servlet. The `ProfileServlet` demonstrates how to access the decoded ID token claims:

  ```java theme={null}
  Principal principal = request.getUserPrincipal();

  if (principal instanceof Auth0JwtPrincipal) {
      Auth0JwtPrincipal auth0JwtPrincipal = (Auth0JwtPrincipal) principal;
      DecodedJWT idToken = auth0JwtPrincipal.getIdToken();

      String name = idToken.getClaim("name").asString();
      String email = idToken.getClaim("email").asString();
      String picture = idToken.getClaim("picture").asString();
      String sub = idToken.getSubject();
  }
  ```

  Common claims available in the ID token:

  * `name` — user's full display name
  * `email` — user's email address
  * `picture` — URL to the user's profile picture
  * `sub` — unique identifier for the user (Auth0 user ID)
</Accordion>

<Accordion title="Customize Login Parameters">
  Add custom parameters to the authorization URL when building it in your `LoginServlet`:

  ```java src/main/java/com/auth0/example/web/LoginServlet.java theme={null}
  String authURL = authenticationController
          .buildAuthorizeUrl(request, response, callbackUrl)
          .withScope(config.getScope())
          .withAudience("https://your-api.example.com")
          .withParameter("screen_hint", "signup")
          .withParameter("ui_locales", "fr")
          .build();
  ```

  Use `.withAudience()` to request an access token for a specific API. Use `.withParameter()` for any additional [authorization parameters](https://auth0.com/docs/api/authentication#authorize-application) supported by Auth0.
</Accordion>

<Accordion title="Store Tokens for API Calls">
  To access the raw tokens for API calls, modify the `Auth0AuthenticationMechanism` to store tokens in the session:

  ```java src/main/java/com/auth0/example/security/Auth0AuthenticationMechanism.java theme={null}
  if (isCallbackRequest(httpServletRequest)) {
      try {
          Tokens tokens = authenticationController.handle(
                  httpServletRequest, httpServletResponse);

          httpServletRequest.getSession().setAttribute(
                  "accessToken", tokens.getAccessToken());

          Auth0JwtCredential auth0JwtCredential =
                  new Auth0JwtCredential(tokens.getIdToken());
          CredentialValidationResult result =
                  identityStoreHandler.validate(auth0JwtCredential);
          return httpMessageContext.notifyContainerAboutLogin(result);
      } catch (IdentityVerificationException e) {
          return httpMessageContext.responseUnauthorized();
      }
  }
  ```

  Then retrieve the access token when calling a protected API:

  ```java theme={null}
  String accessToken = (String) request.getSession().getAttribute("accessToken");
  URL url = new URL("https://your-api.example.com/data");
  HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  conn.setRequestProperty("Authorization", "Bearer " + accessToken);
  ```
</Accordion>

<Accordion title="Log In to an Organization">
  Configure the `AuthenticationController` with an organization ID or name to restrict login to a specific [Auth0 Organization](https://auth0.com/docs/organizations):

  ```java src/main/java/com/auth0/example/security/Auth0AuthenticationProvider.java theme={null}
  @Produces
  public AuthenticationController authenticationController(Auth0AuthenticationConfig config) {
      JwkProvider jwkProvider = new JwkProviderBuilder(config.getDomain()).build();
      return AuthenticationController.newBuilder(
                      config.getDomain(), config.getClientId(), config.getClientSecret())
              .withJwkProvider(jwkProvider)
              .withOrganization("org_YOUR_ORG_ID")
              .build();
  }
  ```

  The SDK automatically validates the `org_id` or `org_name` claim in the ID token to ensure it matches the configured organization.
</Accordion>

***

## Additional Resources

<CardGroup cols={2}>
  <Card title="Auth0 Java MVC SDK" icon="github" href="https://github.com/auth0/auth0-java-mvc-common">
    Source code and issue tracker
  </Card>

  <Card title="API Reference (JavaDoc)" icon="code" href="https://javadoc.io/doc/com.auth0/mvc-auth-commons">
    Detailed API documentation
  </Card>

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

  <Card title="Java EE Sample App" icon="github" href="https://github.com/auth0-samples/auth0-java-ee-sample/tree/master/01-Login">
    Complete sample application on GitHub
  </Card>
</CardGroup>

***

## Common Issues

<AccordionGroup>
  <Accordion title="State mismatch error on callback">
    If you receive an `a0.invalid_state` error after login, the state cookie was not found or does not match the state returned from Auth0.

    Verify that:

    * Your callback URL in the Auth0 Dashboard exactly matches the URL your application constructs, including the port number and protocol.
    * Your browser is not blocking third-party cookies.
    * No reverse proxy or middleware is stripping `Set-Cookie` headers from responses.

    Ensure you are using the three-argument version of both `buildAuthorizeUrl` and `handle`, which uses cookie-based state storage:

    ```java theme={null}
    // Correct — uses cookies for state
    authenticationController.buildAuthorizeUrl(request, response, callbackUrl)
    authenticationController.handle(httpServletRequest, httpServletResponse)
    ```
  </Accordion>

  <Accordion title="CDI beans not discovered">
    If you see errors about injection failures or beans not being found, ensure that:

    * Your application server supports CDI 2.0 (part of Java EE 8)
    * All security classes (`Auth0AuthenticationConfig`, `Auth0AuthenticationProvider`, `Auth0JwtIdentityStore`, `Auth0AuthenticationMechanism`) are annotated with `@ApplicationScoped`
    * `src/main/webapp/WEB-INF/jboss-web.xml` exists with the `jaspitest` security domain configured

    ```xml src/main/webapp/WEB-INF/jboss-web.xml theme={null}
    <jboss-web>
        <security-domain>jaspitest</security-domain>
        <context-root>/</context-root>
    </jboss-web>
    ```

    The `jaspitest` security domain is required for WildFly to enable the JASPIC (Java Authentication SPI for Containers) integration that the Java EE 8 Security API depends on.
  </Accordion>

  <Accordion title="Application server compatibility">
    This quickstart uses the `javax` namespace (Java EE 8). If you are using a server that has migrated to the `jakarta` namespace (Jakarta EE 9+), such as WildFly 27+ or Payara 6+, the code will not compile or run.

    Use a Java EE 8 compatible server:

    * WildFly 14 through 26
    * Payara 5
    * GlassFish 5
    * Open Liberty with Java EE 8 features
  </Accordion>
</AccordionGroup>

***

## Sample Application

A sample Java EE application integrated with Auth0 is available on GitHub:

<Card title="Java EE Sample Application" icon="github" href="https://github.com/auth0-samples/auth0-java-ee-sample/tree/master/01-Login">
  Includes login, logout, user profile, and other examples.
</Card>

Clone and run:

```bash theme={null}
git clone https://github.com/auth0-samples/auth0-java-ee-sample.git
cd auth0-java-ee-sample/01-Login
```

Update the Auth0 configuration values in `src/main/webapp/WEB-INF/web.xml`, then run:

```bash theme={null}
./mvnw clean wildfly:run
```

Point your browser to [http://localhost:8080](http://localhost:8080) and click **Login** to test.

***
