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

> Añada Login, Logout y el perfil de usuario de Auth0 a una aplicación web de Java EE 8 mediante la API de seguridad

# Añada Login a su aplicación Java EE

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="Usa IA para integrar Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  Si usas un asistente de programación con IA como Claude Code, Cursor o GitHub Copilot, puedes añadir la autenticación de Auth0 automáticamente en minutos con [agent skills](https://agentskills.io/home).

  **Instala:**

  ```bash theme={null}
  npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-java-mvc-common
  ```

  **Luego pídele a tu asistente de IA:**

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

  Tu asistente de IA creará automáticamente tu aplicación de Auth0, obtendrá las credenciales, añadirá la dependencia del SDK Auth0 Java MVC Commons, configurará la autenticación con la API de seguridad de Java EE 8 e implementará los flujos de inicio y cierre de sesión. [Documentación completa de agent skills →](/es/docs/quickstart/agent-skills)
</Accordion>

<Note>
  **Requisitos previos:**

  * [Java Development Kit (JDK)](https://www.oracle.com/java/technologies/downloads/) 11 o posterior
  * [Apache Maven](https://maven.apache.org/download.cgi) 3.x
  * Un servidor de aplicaciones compatible con Java EE 8 (por ejemplo, [WildFly](https://www.wildfly.org/) 14+, [Payara](https://www.payara.fish/) 5+ o [GlassFish](https://glassfish.org/) 5+)
  * Una cuenta de Auth0: [regístrate gratis](https://auth0.com/signup)
</Note>

<div id="get-started">
  ## Primeros pasos
</div>

Auth0 le permite añadir rápidamente autenticación a su aplicación y acceder a la información del perfil de usuario. Esta guía muestra cómo integrar Auth0 con cualquier aplicación Java EE, nueva o existente, mediante el SDK `auth0-java-mvc-common` y la API de seguridad de Java EE 8.

<Steps>
  <Step title="Crea un proyecto nuevo" stepNumber={1}>
    Genere un nuevo proyecto WAR de Maven:

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

    Ve al directorio del proyecto:

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

    Cree los directorios fuente de Java:

    ```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="Instala el SDK de Auth0" stepNumber={2}>
    Reemplace el contenido de su `pom.xml` por lo siguiente:

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

    Las dependencias `javaee-api` y `javax.security.enterprise-api` son `provided` porque el servidor de aplicaciones Java EE 8 aporta sus implementaciones en tiempo de ejecución.
  </Step>

  <Step title="Configura tu aplicación de Auth0" stepNumber={3}>
    <Tabs>
      <Tab title="Dashboard">
        1. Ve al [Auth0 Dashboard](https://manage.auth0.com/#/applications) y ve a **Applications > Applications > Create Application**.
        2. Introduce un nombre para tu aplicación (por ejemplo, "My Java EE App").
        3. Selecciona **Regular Web Applications** como tipo de aplicación.
        4. Haz clic en **Create**.
        5. Abre la pestaña **Settings**.
        6. Toma nota de los valores de **Domain**, **Client ID** y **Client Secret**.
        7. Desplázate hacia abajo hasta **Application URIs** y configura:
           * **Allowed Callback URLs**: `http://localhost:8080/callback`
           * **Allowed Logout URLs**: `http://localhost:8080/`
        8. Haz clic en **Save Changes**.
      </Tab>
    </Tabs>

    <Info>
      Asegúrate de [configurar las conexiones](https://auth0.com/docs/get-started/applications/set-up-database-connections) de tu aplicación para que los usuarios puedan iniciar sesión con el proveedor de identidad que prefieran.
    </Info>
  </Step>

  <Step title="Configura la autenticación" stepNumber={4}>
    Actualiza tu `web.xml` para almacenar la configuración de Auth0 como entradas de entorno JNDI. Reemplaza los valores de marcador de posición con el **dominio**, el **ID de cliente** y el **Secreto del cliente** de la configuración de la aplicación de Auth0. Crea un `jboss-web.xml` para configurar el dominio de seguridad JASPIC requerido por la API de seguridad de Java EE 8, un bean CDI `Auth0AuthenticationConfig.java` para leer la configuración desde JNDI, y un productor CDI `Auth0AuthenticationProvider.java` para construir el `AuthenticationController`.

    <Info>
      No incluyas `https://` en el valor de `auth0.domain`. Usa solo el dominio y la región. Por ejemplo: `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="Implementar la seguridad de Java EE" stepNumber={5}>
    La API de seguridad de Java EE 8 usa `HttpAuthenticationMechanism` para gestionar la autenticación. Debe proporcionar implementaciones personalizadas de varias interfaces de seguridad. La anotación `@AutoApplySession` permite que el contenedor cree una sesión para el usuario autenticado, de modo que siga conectado entre solicitudes.

    <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="Añada la funcionalidad para iniciar y cerrar sesión" stepNumber={6}>
    Crea los servlets para login, callback y logout. `LoginServlet` construye la URL de autorización de Auth0 y redirige al usuario. `CallbackServlet` gestiona la redirección después de la autenticación: `Auth0AuthenticationMechanism` intercepta primero esta solicitud para intercambiar el código de autorización por tokens, por lo que el servlet solo tiene que redirigir. `LogoutServlet` invalida la sesión y redirige al endpoint de logout de Auth0.

    <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="Crear la interfaz de usuario" stepNumber={7}>
    Crea los servlets y las páginas JSP para las vistas de inicio y perfil. El `HomeServlet` verifica si existe un principal autenticado y establece los claims del perfil en la solicitud. El `ProfileServlet` muestra el perfil del usuario y los claims JWT, o redirige al Login si no está autenticado.

    <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="Ejecute la aplicación" stepNumber={8}>
    Compile y ejecute la aplicación con el plugin de Maven de WildFly:

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

    La aplicación debería iniciarse y mostrar la URL en la que escucha:

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

    Abre [http://localhost:8080](http://localhost:8080) en tu navegador. Haz clic en el enlace **Login** de la barra de navegación. Se te redirigirá a la página de inicio de sesión de Auth0. Después de autenticarte, se te redirigirá a la [página de perfil](http://localhost:8080/profile), donde se muestran la información de tu usuario y los claims del JWT.

    <Info>
      El ejemplo usa JSP y se ha probado con el servidor de aplicaciones [WildFly](https://wildfly.org/). Es posible que debas ajustar algunos pasos si usas un contenedor compatible con Java EE 8 diferente.
    </Info>
  </Step>
</Steps>

<Check>
  **Punto de control**

  Ahora debería tener una aplicación Java EE protegida con Auth0 totalmente funcional en ejecución en [http://localhost:8080](http://localhost:8080). Los usuarios pueden iniciar sesión, ver su perfil y cerrar sesión.
</Check>

***

<div id="advanced-usage">
  ## Uso avanzado
</div>

<Accordion title="Acceder a la información del perfil de usuario">
  `Auth0JwtPrincipal` está disponible mediante `request.getUserPrincipal()` en cualquier servlet. `ProfileServlet` muestra cómo acceder a los claims decodificados del ID token:

  ```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();
  }
  ```

  Claims comunes disponibles en el ID token:

  * `name` — nombre para mostrar completo del usuario
  * `email` — dirección de correo electrónico del usuario
  * `picture` — URL de la foto de perfil del usuario
  * `sub` — identificador único del usuario (ID de usuario de Auth0)
</Accordion>

<Accordion title="Personalizar los parámetros de Login">
  Agregue parámetros personalizados a la URL de autorización al generarla en su `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()` para solicitar un token de acceso para una API específica. Use `.withParameter()` para cualquier [parámetro de autorización](https://auth0.com/docs/api/authentication#authorize-application) adicional admitido por Auth0.
</Accordion>

<Accordion title="Almacenar tokens para llamadas a API">
  Para acceder a los tokens sin modificar para llamadas a API, modifique `Auth0AuthenticationMechanism` para almacenar los tokens en la sesión:

  ```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();
      }
  }
  ```

  Luego, recupere el token de acceso al llamar a una API protegida:

  ```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="Iniciar sesión en una organización">
  Configure `AuthenticationController` con un ID o nombre de organización para restringir el Login a una [Organización de Auth0](https://auth0.com/docs/organizations) específica:

  ```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();
  }
  ```

  El SDK valida automáticamente el claim `org_id` o `org_name` en el ID token para garantizar que coincida con la organización configurada.
</Accordion>

***

<div id="additional-resources">
  ## Recursos adicionales
</div>

<CardGroup cols={2}>
  <Card title="Auth0 Java MVC SDK" icon="github" href="https://github.com/auth0/auth0-java-mvc-common">
    Código fuente y seguimiento de problemas
  </Card>

  <Card title="Referencia de la API (JavaDoc)" icon="code" href="https://javadoc.io/doc/com.auth0/mvc-auth-commons">
    Documentación detallada de la API
  </Card>

  <Card title="Foro de la comunidad" icon="comments" href="https://community.auth0.com/">
    Obtén ayuda de la comunidad de Auth0
  </Card>

  <Card title="Aplicación de ejemplo de Java EE" icon="github" href="https://github.com/auth0-samples/auth0-java-ee-sample/tree/master/01-Login">
    Aplicación de ejemplo completa en GitHub
  </Card>
</CardGroup>

***

<div id="common-issues">
  ## Problemas comunes
</div>

<AccordionGroup>
  <Accordion title="Error de discrepancia de estado en el callback">
    Si recibes un error `a0.invalid_state` después del Login, significa que no se encontró la cookie de estado o que no coincide con el estado devuelto por Auth0.

    Verifica que:

    * La URL de devolución de llamada en el Auth0 Dashboard coincida exactamente con la URL que construye tu aplicación, incluido el número de puerto y el protocolo.
    * Tu navegador no esté bloqueando cookies de terceros.
    * Ningún proxy inverso ni middleware esté eliminando los encabezados `Set-Cookie` de las respuestas.

    Asegúrate de usar la versión de tres argumentos de `buildAuthorizeUrl` y `handle`, que utiliza almacenamiento de estado basado en cookies:

    ```java theme={null}
    // Correcto — usa cookies para el estado
    authenticationController.buildAuthorizeUrl(request, response, callbackUrl)
    authenticationController.handle(httpServletRequest, httpServletResponse)
    ```
  </Accordion>

  <Accordion title="Beans de CDI no detectados">
    Si ves errores de inyección o mensajes de que no se encuentran beans, asegúrate de que:

    * Tu servidor de aplicaciones sea compatible con CDI 2.0 (parte de Java EE 8)
    * Todas las clases de seguridad (`Auth0AuthenticationConfig`, `Auth0AuthenticationProvider`, `Auth0JwtIdentityStore`, `Auth0AuthenticationMechanism`) estén anotadas con `@ApplicationScoped`
    * Exista `src/main/webapp/WEB-INF/jboss-web.xml` con el dominio de seguridad `jaspitest` configurado

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

    El dominio de seguridad `jaspitest` es necesario para que WildFly habilite la integración con JASPIC (Java Authentication SPI for Containers), de la que depende la API de seguridad de Java EE 8.
  </Accordion>

  <Accordion title="Compatibilidad del servidor de aplicaciones">
    Este inicio rápido usa el espacio de nombres `javax` (Java EE 8). Si usas un servidor que ya migró al espacio de nombres `jakarta` (Jakarta EE 9+), como WildFly 27+ o Payara 6+, el código no se compilará ni se ejecutará.

    Usa un servidor compatible con Java EE 8:

    * WildFly 14 a 26
    * Payara 5
    * GlassFish 5
    * Open Liberty con características de Java EE 8
  </Accordion>
</AccordionGroup>

***

<div id="sample-application">
  ## Aplicación de ejemplo
</div>

En GitHub hay disponible una aplicación de ejemplo de Java EE integrada con Auth0:

<Card title="Aplicación de ejemplo de Java EE" icon="github" href="https://github.com/auth0-samples/auth0-java-ee-sample/tree/master/01-Login">
  Incluye Login, cierre de sesión, perfil de usuario y otros ejemplos.
</Card>

Clónela y ejecútela:

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

Actualiza los valores de configuración de Auth0 en `src/main/webapp/WEB-INF/web.xml` y, a continuación, ejecuta:

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

Ve a [http://localhost:8080](http://localhost:8080) en tu navegador y haz clic en **Login** para probarlo.

***
