> ## 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.

> Security API を使用して、Java EE 8 の Web アプリケーションに Auth0 のログイン、ログアウト、ユーザープロファイルを追加する

# 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="AI を使用して Auth0 を統合する" icon="microchip-ai" iconType="solid" defaultOpen>
  Claude Code、Cursor、GitHub Copilot などの AI コーディングアシスタントを使用している場合は、[agent skills](https://agentskills.io/home) を使うことで、数分で Auth0 認証を自動的に追加できます。

  **インストール:**

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

  **次に、AI アシスタントに次のように依頼します。**

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

  AI アシスタントは、Auth0 アプリケーションの作成、認証情報の取得、Auth0 Java MVC Commons SDK 依存関係の追加、Java EE 8 Security API を使用した認証の構成、ログイン/ログアウトフローの実装を自動的に行います。[agent skills の完全なドキュメント →](/ja/docs/quickstart/agent-skills)
</Accordion>

<Note>
  **前提条件:**

  * [Java Development Kit (JDK)](https://www.oracle.com/java/technologies/downloads/) 11 以降
  * [Apache Maven](https://maven.apache.org/download.cgi) 3.x
  * Java EE 8 対応アプリケーションサーバー (例: [WildFly](https://www.wildfly.org/) 14 以降、[Payara](https://www.payara.fish/) 5 以降、または [GlassFish](https://glassfish.org/) 5 以降)
  * Auth0 アカウント — [無料でサインアップ](https://auth0.com/signup)
</Note>

<div id="get-started">
  ## はじめに
</div>

Auth0 を使用すると、アプリケーションに認証をすばやく追加し、ユーザープロフィール情報にアクセスできます。このガイドでは、`auth0-java-mvc-common` SDK と Java EE 8 Security API を使用して、新規または既存の Java EE アプリケーションに Auth0 を統合する方法を説明します。

<Steps>
  <Step title="新しいプロジェクトを作成" stepNumber={1}>
    新しい Maven WAR プロジェクトを作成します:

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

    プロジェクトディレクトリに移動します。

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

    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="Auth0 SDK をインストールする" stepNumber={2}>
    `pom.xml` の内容を以下のように置き換えます。

    ```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` と `javax.security.enterprise-api` の依存関係が `provided` になっているのは、Java EE 8 アプリケーションサーバーが実行時にそれらの実装を提供するためです。
  </Step>

  <Step title="Auth0アプリケーションを設定する" stepNumber={3}>
    <Tabs>
      <Tab title="ダッシュボード">
        1. [Auth0 Dashboard](https://manage.auth0.com/#/applications) に移動し、**Applications > Applications > Create Application** の順に選択します。
        2. アプリケーションの名前 (例: "My Java EE App") を入力します。
        3. アプリケーションの種類として **Regular Web Applications** を選択します。
        4. **Create** を選択します。
        5. **Settings** タブを開きます。
        6. **Domain**、**Client ID**、**Client Secret** の値を控えます。
        7. **Application URIs** までスクロールし、以下を設定します。
           * **Allowed Callback URLs**: `http://localhost:8080/callback`
           * **Allowed Logout URLs**: `http://localhost:8080/`
        8. **Save Changes** を選択します。
      </Tab>
    </Tabs>

    <Info>
      ユーザーが使用したいIDプロバイダーでログインできるように、アプリケーションの[接続を設定](https://auth0.com/docs/get-started/applications/set-up-database-connections)してください。
    </Info>
  </Step>

  <Step title="認証を設定する" stepNumber={4}>
    `web.xml` を更新して、Auth0 の設定を JNDI 環境エントリとして保存します。プレースホルダーの値は、Auth0 アプリケーション設定の**ドメイン**、**クライアントID**、**クライアントシークレット**に置き換えてください。続いて、Java EE 8 Security API が必要とする JASPIC セキュリティドメインを設定する `jboss-web.xml`、JNDI から設定を読み込む CDI Bean の `Auth0AuthenticationConfig.java`、および `AuthenticationController` を構築する CDI プロデューサーの `Auth0AuthenticationProvider.java` を作成します。

    <Info>
      `auth0.domain` の値には `https://` を含めないでください。ドメインとリージョンのみを指定してください。例: `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="Java EE のセキュリティを実装する" stepNumber={5}>
    Java EE 8 Security API では、認証の処理に `HttpAuthenticationMechanism` を使用します。そのため、複数のセキュリティインターフェースのカスタム実装を用意する必要があります。`@AutoApplySession` アノテーションを使用すると、コンテナが認証済みユーザーのセッションを作成し、複数のリクエストにまたがってログイン状態を維持できます。

    <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="ログイン機能とログアウト機能を追加" stepNumber={6}>
    ログイン、コールバック、ログアウト用のサーブレットを作成します。`LoginServlet` は Auth0 の認可 URL を生成し、ユーザーをリダイレクトします。`CallbackServlet` は認証後のリダイレクトを処理します。`Auth0AuthenticationMechanism` が最初にこのリクエストをインターセプトし、認可 code をトークンに交換するため、このサーブレットで必要なのはリダイレクトだけです。`LogoutServlet` はセッションをクリアして、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="ユーザーインターフェースを作成する" stepNumber={7}>
    ホームビューとプロフィールビュー用のサーブレットとJSPページを作成します。`HomeServlet`は認証済みプリンシパルを確認し、リクエストにプロフィールクレームを設定します。`ProfileServlet`はユーザーのプロフィールとJWTクレームを表示します。未認証の場合はログインページにリダイレクトします。

    <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="アプリケーションを実行する" stepNumber={8}>
    WildFly Maven プラグインを使用して、アプリケーションをビルドして実行します。

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

    アプリケーションが起動し、リッスンしているURLが表示されるはずです:

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

    ブラウザーで [http://localhost:8080](http://localhost:8080) を開きます。ナビゲーションバーの **Login** リンクをクリックします。Auth0 のログインページにリダイレクトされます。認証後、[プロフィールページ](http://localhost:8080/profile) にリダイレクトされ、ユーザー情報と JWT クレームが表示されます。

    <Info>
      このサンプルは JSP を使用しており、[WildFly](https://wildfly.org/) アプリケーションサーバーでテストされています。別の Java EE 8 互換コンテナを使用している場合は、一部の手順を調整する必要がある場合があります。
    </Info>
  </Step>
</Steps>

<Check>
  **チェックポイント**

  これで、[http://localhost:8080](http://localhost:8080) で Auth0 によって保護された、完全に機能する Java EE アプリケーションが実行されているはずです。ユーザーはログイン、プロフィールの表示、ログアウトを行えます。
</Check>

***

<div id="advanced-usage">
  ## 高度な使用例
</div>

<Accordion title="ユーザープロフィール情報にアクセスする">
  `Auth0JwtPrincipal` は、任意のサーブレットで `request.getUserPrincipal()` を介して利用できます。`ProfileServlet` では、デコードされた IDトークン のクレームにアクセスする方法を示しています。

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

  IDトークン で一般的に使用できるクレーム:

  * `name` — ユーザーの表示名 (フルネーム)
  * `email` — ユーザーのメールアドレス
  * `picture` — ユーザーのプロフィール画像の URL
  * `sub` — ユーザーの一意な識別子 (Auth0 ユーザー ID)
</Accordion>

<Accordion title="ログインパラメーターをカスタマイズする">
  `LoginServlet` で認可 URL を構築する際に、カスタムパラメーターを追加します。

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

  特定の API 向けのアクセストークンをリクエストするには `.withAudience()` を使用します。Auth0 がサポートする追加の[認可パラメーター](https://auth0.com/docs/api/authentication#authorize-application)を指定するには `.withParameter()` を使用します。
</Accordion>

<Accordion title="API 呼び出し用にトークンを保存する">
  API 呼び出しで生のトークンにアクセスするには、トークンをセッションに保存するよう `Auth0AuthenticationMechanism` を変更します。

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

  次に、保護された 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="組織にログインする">
  特定の [Auth0 Organization](https://auth0.com/docs/organizations) にログインを制限するには、組織 ID または名前を指定して `AuthenticationController` を設定します。

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

  SDK は、設定した組織と一致することを確認するため、IDトークン 内の `org_id` または `org_name` クレームを自動的に検証します。
</Accordion>

***

<div id="additional-resources">
  ## 追加リソース
</div>

<CardGroup cols={2}>
  <Card title="Auth0 Java MVC SDK" icon="github" href="https://github.com/auth0/auth0-java-mvc-common">
    ソースコードと Issue トラッカー
  </Card>

  <Card title="API リファレンス（JavaDoc）" icon="code" href="https://javadoc.io/doc/com.auth0/mvc-auth-commons">
    詳細な API ドキュメント
  </Card>

  <Card title="コミュニティフォーラム" icon="comments" href="https://community.auth0.com/">
    Auth0 コミュニティでサポートを受ける
  </Card>

  <Card title="Java EE サンプルアプリ" icon="github" href="https://github.com/auth0-samples/auth0-java-ee-sample/tree/master/01-Login">
    GitHub 上の完全なサンプルアプリケーション
  </Card>
</CardGroup>

***

<div id="common-issues">
  ## よくある問題
</div>

<AccordionGroup>
  <Accordion title="コールバックでの state 不一致エラー">
    ログイン後に `a0.invalid_state` エラーが発生する場合、state Cookie が見つからないか、Auth0 から返された state と一致していません。

    次の点を確認してください。

    * Auth0 Dashboard のコールバック URL が、ポート番号とプロトコルを含めて、アプリケーションが構築する URL と完全に一致していること。
    * ブラウザーがサードパーティ Cookie をブロックしていないこと。
    * リバースプロキシまたはミドルウェアによって、レスポンスから `Set-Cookie` ヘッダーが削除されていないこと。

    Cookie ベースの state 保存を使用する、`buildAuthorizeUrl` と `handle` の両方の 3 引数版を使用していることを確認してください。

    ```java theme={null}
    // 正しい例 — state に Cookie を使用
    authenticationController.buildAuthorizeUrl(request, response, callbackUrl)
    authenticationController.handle(httpServletRequest, httpServletResponse)
    ```
  </Accordion>

  <Accordion title="CDI Bean が検出されない">
    インジェクションの失敗や Bean が見つからないというエラーが表示される場合は、次の点を確認してください。

    * アプリケーションサーバーが CDI 2.0 (Java EE 8 の一部) をサポートしていること
    * すべてのセキュリティクラス (`Auth0AuthenticationConfig`、`Auth0AuthenticationProvider`、`Auth0JwtIdentityStore`、`Auth0AuthenticationMechanism`) に `@ApplicationScoped` アノテーションが付与されていること
    * `src/main/webapp/WEB-INF/jboss-web.xml` が存在し、`jaspitest` セキュリティドメインが設定されていること

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

    Java EE 8 Security API が依存する JASPIC (Java Authentication SPI for Containers) 統合を WildFly で有効にするには、`jaspitest` セキュリティドメインが必要です。
  </Accordion>

  <Accordion title="アプリケーションサーバーの互換性">
    このクイックスタートでは `javax` 名前空間 (Java EE 8) を使用します。WildFly 27+ や Payara 6+ など、`jakarta` 名前空間 (Jakarta EE 9+) に移行したサーバーを使用している場合、コードはコンパイルも実行もできません。

    Java EE 8 互換のサーバーを使用してください。

    * WildFly 14 ～ 26
    * Payara 5
    * GlassFish 5
    * Java EE 8 機能を有効化した Open Liberty
  </Accordion>
</AccordionGroup>

***

<div id="sample-application">
  ## サンプルアプリケーション
</div>

Auth0 と統合された Java EE のサンプルアプリケーションが GitHub で公開されています。

<Card title="Java EE サンプルアプリケーション" icon="github" href="https://github.com/auth0-samples/auth0-java-ee-sample/tree/master/01-Login">
  ログイン、ログアウト、ユーザープロファイルなどの例が含まれています。
</Card>

クローンして実行します。

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

`src/main/webapp/WEB-INF/web.xml` の Auth0 の設定値を更新してから、次を実行します。

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

ブラウザーで [http://localhost:8080](http://localhost:8080) を開き、**Login** をクリックしてテストしてください。

***
