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

> 複数のカスタムドメインで動作するように Auth0 SDK を設定する方法について説明します。

# 複数のカスタムドメイン向けの SDK 設定

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>;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****マスク済み*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

[複数のカスタムドメイン](/ja/docs/customize/custom-domains/multiple-custom-domains)を使用する場合は、認証時に適切なカスタムドメインを使用するよう、Auth0 SDK を設定する必要があります。このガイドでは、さまざまなプラットフォームやシナリオにおける SDK の設定方法について説明します。

<div id="key-concepts">
  ## 主な概念
</div>

<div id="domain-parameter">
  ### ドメイン パラメーター
</div>

すべての Auth0 SDK では、認証に使用する Auth0 ドメインを指定する `domain` パラメーターが必要です。カスタムドメインを使用する場合は、このパラメーターに Auth0 の標準ドメインではなく、カスタムドメインを設定します。

**カスタムドメインを使用しない場合:**

```
domain: 'tenant.auth0.com'
```

**カスタムドメインを使用する場合:**

```
domain: 'login.example.com'
```

<div id="token-issuer">
  ### トークンの発行元
</div>

カスタムドメインを使用している場合、トークンの `iss` (発行元) クレームには、カスタムドメインが設定されます。

```json theme={null}
{
  "iss": "https://login.example.com/",
  "sub": "auth0|123456",
  "aud": "your-client-id"
}
```

トークン検証で、カスタムドメインを有効な発行元として受け入れるように設定する必要があります。

<div id="authentication-sdks">
  ## 認証 SDK
</div>

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  MCD を使用する場合、すべてのカスタムドメインの提供と検証はお客様の責任となります。SDK でドメインリゾルバー関数を使用してテナントのカスタムドメインを解決するよう設定する場合は、解決されるすべてのドメインが信頼できるものであることをお客様自身で必ず確認してください。ドメインリゾルバーの設定を誤ると、relying party で認証がバイパスされたり、アプリケーションがサーバーサイドリクエストフォージェリにさらされたりする可能性があります。ドメインおよびプロキシサーバーを適切に設定しないと、重大なセキュリティ脆弱性が生じるおそれがあり、これについて Okta は責任を負いません。
</Callout>

<div id="auth0-spa-sdk-javascript">
  ### Auth0 SPA SDK (JavaScript)
</div>

[Auth0 SPA SDK](https://github.com/auth0/auth0-spa-js) を使用するシングルページアプリケーションの場合は、次のように設定します。

<AuthCodeGroup>
  ```javascript Static Configuration theme={null}
  import { createAuth0Client } from '@auth0/auth0-spa-js';

  const auth0 = await createAuth0Client({
    domain: 'login.example.com',  // カスタムドメイン
    clientId: 'YOUR_CLIENT_ID',
    authorizationParams: {
      redirect_uri: window.location.origin
    }
  });
  ```

  ```javascript Dynamic Configuration theme={null}
  import { createAuth0Client } from '@auth0/auth0-spa-js';

  // アプリケーションのコンテキストに基づいてドメインを判定
  function getAuth0Domain() {
    const hostname = window.location.hostname;

    // アプリケーションのドメインを Auth0 のカスタムドメインにマッピング
    if (hostname.includes('app1.example.com')) {
      return 'login.brand1.com';
    } else if (hostname.includes('app2.example.com')) {
      return 'login.brand2.com';
    }

    // デフォルトのカスタムドメイン
    return 'login.example.com';
  }

  const auth0 = await createAuth0Client({
    domain: getAuth0Domain(),
    clientId: 'YOUR_CLIENT_ID',
    authorizationParams: {
      redirect_uri: window.location.origin
    }
  });
  ```

  ```javascript Environment Variables theme={null}
  import { createAuth0Client } from '@auth0/auth0-spa-js';

  const auth0 = await createAuth0Client({
    domain: process.env.REACT_APP_AUTH0_DOMAIN,  // .env ファイルから取得
    clientId: process.env.REACT_APP_AUTH0_CLIENT_ID,
    authorizationParams: {
      redirect_uri: window.location.origin
    }
  });
  ```
</AuthCodeGroup>

<div id="nextjs">
  ### Next.js
</div>

[Auth0 Next.js SDK](https://github.com/auth0/nextjs-auth0) (v4+) を使用する Next.js アプリケーションの場合:

<AuthCodeGroup>
  ```typescript 静的設定 theme={null}
  import { Auth0Client } from '@auth0/nextjs-auth0/server';

  const auth0 = new Auth0Client({
    domain: 'login.example.com',        // カスタムドメイン
    clientId: process.env.AUTH0_CLIENT_ID,
    clientSecret: process.env.AUTH0_CLIENT_SECRET,
    appBaseUrl: process.env.APP_BASE_URL,
    secret: process.env.AUTH0_SECRET
  });
  ```

  ```typescript 動的設定（マルチブランド） theme={null}
  import { Auth0Client } from '@auth0/nextjs-auth0/server';

  const auth0 = new Auth0Client({
    domain: ({ headers }) => {
      // アプリケーションのホストを Auth0 のカスタムドメインにマッピングする
      const host = headers.get('host') || '';

      if (host.includes('brand1.example.com')) {
        return 'login.brand1.com';
      } else if (host.includes('brand2.example.com')) {
        return 'login.brand2.com';
      }

      return 'login.example.com';  // デフォルトドメイン
    },
    clientId: process.env.AUTH0_CLIENT_ID,
    clientSecret: process.env.AUTH0_CLIENT_SECRET,
    appBaseUrl: process.env.APP_BASE_URL,
    secret: process.env.AUTH0_SECRET
  });
  ```

  ```typescript 動的設定（B2B SaaS） theme={null}
  import { Auth0Client } from '@auth0/nextjs-auth0/server';

  // テナント識別子をカスタムドメインにマッピングする（データベース、キャッシュなどから）
  async function resolveTenantDomain(host: string): Promise<string> {
    // サブドメインからテナント識別子を抽出する
    const subdomain = host.split('.')[0];

    // このテナントのカスタムドメインを取得する（例: データベースから）
    const tenantConfig = await getTenantConfig(subdomain);

    return tenantConfig?.customDomain || 'login.example.com';
  }

  const auth0 = new Auth0Client({
    domain: async ({ headers }) => {
      const host = headers.get('host') || '';
      return resolveTenantDomain(host);
    },
    clientId: process.env.AUTH0_CLIENT_ID,
    clientSecret: process.env.AUTH0_CLIENT_SECRET,
    appBaseUrl: process.env.APP_BASE_URL,
    secret: process.env.AUTH0_SECRET
  });
  ```

  ```bash 環境変数 theme={null}
  # .env.local

  # Auth0 の設定（単一テナントで複数のカスタムドメインを使用）
  AUTH0_DOMAIN=login.example.com           # デフォルトまたはフォールバック用のカスタムドメイン
  AUTH0_CLIENT_ID=your_client_id
  AUTH0_CLIENT_SECRET=your_client_secret
  APP_BASE_URL=http://localhost:3000
  AUTH0_SECRET=your-long-random-secret
  ```
</AuthCodeGroup>

**Next.js で MCD を使用する際の主な概念:**

* **単一の Auth0 テナント、複数のドメイン**: すべてのカスタムドメインは同じ Auth0 テナントに属するため、同じ `clientId` と `clientSecret` を共有します。
* **DomainResolver 関数**: `domain` パラメータには、関数 `(config: { headers: Headers; url?: URL }) => Promise<string> | string` を指定できます。これにより、受信したリクエストヘッダーに基づいて、リクエストごとに動的にドメインを解決できます。
* **インスタンスキャッシュ**: SDK は、パフォーマンス向上のために、制限付き LRU キャッシュ (最大 100 エントリ) を使用して、ドメインごとに `Auth0Client` インスタンスを自動的にキャッシュします。
* **セッションの分離**: あるカスタムドメイン経由で作成されたセッションはそのドメインに限定されるため、別のドメインのセッションと相互に使用することはできません。
* **URL パラメータ**: リゾルバ内の `url` パラメータは、Server Components と Server Actions では `undefined` です。使用できるのは middleware または API ルート内のみです。
* **ディスカバリキャッシュの調整**: `discoveryCache` オプションを使用して OIDC メタデータのキャッシュを設定します。
  ```typescript theme={null}
  const auth0 = new Auth0Client({
    // ... 他の設定
    discoveryCache: {
      ttl: 600,      // 10 分間キャッシュする（デフォルト）
      maxEntries: 100  // キャッシュされる issuer の最大数（デフォルト: 100、LRU による削除）
    }
  });
  ```

<div id="auth0-react-sdk">
  ### Auth0 React SDK
</div>

React アプリケーションで [Auth0 React SDK](https://github.com/auth0/auth0-react) を使用する場合:

```jsx theme={null}
import { Auth0Provider } from '@auth0/auth0-react';

function App() {
  return (
    <Auth0Provider
      domain="login.example.com"
      clientId="YOUR_CLIENT_ID"
      authorizationParams={{
        redirect_uri: window.location.origin
      }}
    >
      <MyApp />
    </Auth0Provider>
  );
}
```

複数ドメインの構成では:

```jsx theme={null}
import { Auth0Provider } from '@auth0/auth0-react';

function App() {
  // 環境またはコンテキストに基づいてカスタムドメインを決定する
  const auth0Domain = process.env.REACT_APP_AUTH0_DOMAIN || 'login.example.com';

  return (
    <Auth0Provider
      domain={auth0Domain}
      clientId={process.env.REACT_APP_AUTH0_CLIENT_ID}
      authorizationParams={{
        redirect_uri: window.location.origin
      }}
    >
      <MyApp />
    </Auth0Provider>
  );
}
```

<div id="auth0js">
  ### Auth0.js
</div>

[Auth0.js](https://github.com/auth0/auth0.js) を使用するアプリケーションの場合:

```javascript theme={null}
const webAuth = new auth0.WebAuth({
  domain: 'login.example.com',
  clientID: 'YOUR_CLIENT_ID',
  redirectUri: window.location.origin + '/callback',
  responseType: 'code',
  scope: 'openid profile email'
});

// ログインを開始
webAuth.authorize();
```

<div id="nodejs-express">
  ### Node.js (Express)
</div>

[express-openid-connect](https://github.com/auth0/express-openid-connect) を使用する Node.js アプリケーションでは、

```javascript theme={null}
const { auth } = require('express-openid-connect');

app.use(
  auth({
    authRequired: false,
    auth0Logout: true,
    issuerBaseURL: 'https://login.example.com',  // カスタムドメイン
    baseURL: 'http://localhost:3000',
    clientID: 'YOUR_CLIENT_ID',
    secret: 'YOUR_CLIENT_SECRET'
  })
);
```

マルチテナントのシナリオでは:

```javascript theme={null}
const { auth } = require('express-openid-connect');

// リクエストごとにカスタムドメインを決定するミドルウェア
app.use((req, res, next) => {
  // サブドメイン、パス、またはヘッダーからテナント識別子を抽出する
  const tenant = req.subdomains[0] || 'default';

  // テナントをカスタムドメインにマッピングする
  const domainMap = {
    'customer1': 'login.customer1.com',
    'customer2': 'login.customer2.com',
    'default': 'login.example.com'
  };

  req.auth0Domain = domainMap[tenant] || domainMap.default;
  next();
});

// 動的な認証設定
app.use((req, res, next) => {
  auth({
    authRequired: false,
    auth0Logout: true,
    issuerBaseURL: `https://${req.auth0Domain}`,
    baseURL: req.protocol + '://' + req.get('host'),
    clientID: process.env.AUTH0_CLIENT_ID,
    secret: process.env.AUTH0_CLIENT_SECRET
  })(req, res, next);
});
```

<div id="mobile-sdks">
  ### モバイル向け SDK
</div>

<div id="ios-swift">
  #### iOS (Swift)
</div>

[Auth0.swift](https://github.com/auth0/Auth0.swift)を使用する場合:

```swift theme={null}
import Auth0

let auth0 = Auth0
    .webAuth(clientId: "YOUR_CLIENT_ID", domain: "login.example.com")

auth0
    .scope("openid profile email")
    .start { result in
        switch result {
        case .success(let credentials):
            print("Obtained credentials: \(credentials)")
        case .failure(let error):
            print("Failed with: \(error)")
        }
    }
```

ドメインを動的に選択する場合:

```swift theme={null}
import Auth0

class AuthService {
    private let clientId = "YOUR_CLIENT_ID"

    func getAuth0Domain() -> String {
        // アプリの設定に基づいてドメインを決定する
        if let savedDomain = UserDefaults.standard.string(forKey: "auth0Domain") {
            return savedDomain
        }
        return "login.example.com" // デフォルト
    }

    func login(completion: @escaping (Result<Credentials, Error>) -> Void) {
        Auth0
            .webAuth(clientId: clientId, domain: getAuth0Domain())
            .scope("openid profile email")
            .start { result in
                completion(result)
            }
    }
}
```

<div id="android-kotlin">
  #### Android (Kotlin)
</div>

[Auth0.Android](https://github.com/auth0/Auth0.Android) を使用する場合は:

```kotlin theme={null}
import com.auth0.android.Auth0
import com.auth0.android.authentication.AuthenticationAPIClient
import com.auth0.android.provider.WebAuthProvider
import com.auth0.android.result.Credentials

val account = Auth0.getInstance(
    "YOUR_CLIENT_ID",
    "login.example.com"  // カスタムドメイン
)

WebAuthProvider.login(account)
    .withScheme("demo")
    .withScope("openid profile email")
    .start(this, object : Callback<Credentials, AuthenticationException> {
        override fun onSuccess(credentials: Credentials) {
            // 成功時の処理
        }

        override fun onFailure(exception: AuthenticationException) {
            // 失敗時の処理
        }
    })
```

複数ドメインをサポートするには:

```kotlin theme={null}
class AuthManager(private val context: Context) {
    private val clientId = "YOUR_CLIENT_ID"

    private fun getAuth0Domain(): String {
        // 共有プリファレンスまたはアプリ設定から取得
        val prefs = context.getSharedPreferences("auth", Context.MODE_PRIVATE)
        return prefs.getString("auth0_domain", "login.example.com") ?: "login.example.com"
    }

    fun login(callback: Callback<Credentials, AuthenticationException>) {
        val account = Auth0.getInstance(clientId, getAuth0Domain())

        WebAuthProvider.login(account)
            .withScheme("demo")
            .withScope("openid profile email")
            .start(context, callback)
    }
}
```

<div id="react-native">
  #### React Native
</div>

[react-native-auth0](https://github.com/auth0/react-native-auth0) を使用する場合は、次のとおりです。

```javascript theme={null}
import Auth0 from 'react-native-auth0';

const auth0 = new Auth0({
  domain: 'login.example.com',
  clientId: 'YOUR_CLIENT_ID'
});

// ログイン
auth0.webAuth
  .authorize({
    scope: 'openid profile email'
  })
  .then(credentials => {
    console.log('Logged in!');
  })
  .catch(error => {
    console.log(error);
  });
```

<div id="flutter">
  ### Flutter
</div>

[flutter\_auth0](https://github.com/auth0/auth0-flutter) を使用する場合:

```dart theme={null}
import 'package:auth0_flutter/auth0_flutter.dart';

final auth0 = Auth0(
  'login.example.com',
  'YOUR_CLIENT_ID'
);

// ログイン
try {
  final credentials = await auth0.webAuthentication().login();
  print('Logged in successfully');
} catch (e) {
  print('Login failed: $e');
}
```

<div id="management-sdks">
  ## Management SDKs
</div>

Management SDK は、Auth0 の Management API と連携するために使用します。カスタムドメインを使用している場合は、`auth0-custom-domain` ヘッダーを含めるか、[デフォルトドメイン](/ja/docs/customize/custom-domains/multiple-custom-domains/default-domain)を使用する必要がある場合があります。

<div id="nodejs-management-sdk">
  ### Node.js Management SDK
</div>

```javascript theme={null}
import { ManagementClient, CustomDomainHeader } from "auth0";

// グローバルカスタムドメイン（ホワイトリストに登録されたすべてのリクエストに送信）
const management = new ManagementClient({
  domain: 'tenant.auth0.com',
  clientId: 'YOUR_M2M_CLIENT_ID',
  clientSecret: 'YOUR_M2M_CLIENT_SECRET',
  withCustomDomainHeader: 'login.example.com', 
});

// ユーザー一覧取得（ホワイトリストに登録されたエンドポイント - ヘッダーは自動送信）
const users = await management.users.getAll();

// リクエスト単位の上書き（グローバル設定より優先）
const reqOptions = {
  ...CustomDomainHeader("specific-user-request.exampleco.com"),
};
const response = await management.users.getAll({}, reqOptions);
```

<div id="python-management-sdk">
  ### Python Management SDK
</div>

```python theme={null}
from auth0.management import ManagementClient, CustomDomainHeader

# グローバルカスタムドメイン（ホワイトリストに登録されたすべてのリクエストに送信）
client = ManagementClient(
    domain='tenant.auth0.com',
    client_id='YOUR_M2M_CLIENT_ID',
    client_secret='YOUR_M2M_CLIENT_SECRET',
    custom_domain='login.example.com',
)

# ユーザー一覧取得（ホワイトリスト登録済みエンドポイント - ヘッダーは自動送信）
users = client.users.list()

# リクエストごとの上書き（グローバル設定より優先）
client.users.create(
    connection='Username-Password-Authentication',
    email='user@example.com',
    password='SecurePass123!',
    request_options=CustomDomainHeader('login.brand2.com'),
)
```

<div id="go-management-sdk">
  ### Go Management SDK
</div>

```go theme={null}
import (
    "context"
    management "github.com/auth0/go-auth0/v2/management/client"
    "github.com/auth0/go-auth0/v2/management/option"
)

// クライアントレベル: ホワイトリスト登録済みエンドポイントにカスタムドメインヘッダーを自動適用
mgmt, err := management.New(
    "{yourDomain}",
    option.WithClientCredentials("{yourClientId}", "{yourClientSecret}"),
    option.WithCustomDomainHeader("login.example.com"),
)
if err != nil {
    // エラー処理
}

// ユーザー一覧取得（ホワイトリスト登録済みエンドポイント - ヘッダーは自動送信）
userList, err := mgmt.Users.List(context.Background(), nil)

// リクエストごとの上書き（クライアントレベルより優先）
userList, err := mgmt.Users.List(
    context.Background(),
    nil,
    option.WithCustomDomainHeader("specific-request.exampleco.com"),
)
```

<div id="token-validation">
  ## トークンの検証
</div>

カスタムドメインを使用する場合は、発行元としてカスタムドメインを許可するようにトークン検証を更新します。

<div id="nodejs-express">
  ### Node.js (Express)
</div>

[express-jwt](https://github.com/auth0/express-jwt) または [jose](https://github.com/panva/jose) を使用する場合:

```javascript theme={null}
const { expressjwt } = require('express-jwt');
const { expressJwtSecret } = require('jwks-rsa');

app.use(
  expressjwt({
    secret: expressJwtSecret({
      cache: true,
      rateLimit: true,
      jwksUri: 'https://login.example.com/.well-known/jwks.json'  // カスタムドメイン
    }),
    audience: 'YOUR_API_IDENTIFIER',
    issuer: 'https://login.example.com/',  // 発行元としてのカスタムドメイン
    algorithms: ['RS256']
  })
);
```

複数のカスタムドメインを使用する場合:

```javascript theme={null}
const validIssuers = [
  'https://login.brand1.com/',
  'https://login.brand2.com/',
  'https://login.example.com/'
];

app.use(
  expressjwt({
    secret: expressJwtSecret({
      cache: true,
      rateLimit: true,
      jwksRequestsPerMinute: 5,
      jwksUri: (req) => {
        // トークンから発行元を抽出してJWKS URIを決定する
        const token = req.headers.authorization?.split(' ')[1];
        if (token) {
          const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
          return `${payload.iss}.well-known/jwks.json`;
        }
        return 'https://login.example.com/.well-known/jwks.json';
      }
    }),
    audience: 'YOUR_API_IDENTIFIER',
    issuer: validIssuers,  // 複数の発行元を許可する
    algorithms: ['RS256']
  })
);
```

<div id="python-flask">
  ### Python (Flask)
</div>

[python-jose](https://github.com/mpdavis/python-jose) を使用する場合は、以下のとおりです。

```python theme={null}
from jose import jwt
from functools import wraps
from flask import request, jsonify

def get_token_auth_header():
    auth = request.headers.get('Authorization', None)
    if not auth:
        raise Exception('Authorization header is expected')

    parts = auth.split()
    if parts[0].lower() != 'bearer':
        raise Exception('Authorization header must start with Bearer')
    elif len(parts) == 1:
        raise Exception('Token not found')
    elif len(parts) > 2:
        raise Exception('Authorization header must be Bearer token')

    return parts[1]

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = get_token_auth_header()

        # 複数のカスタムドメインをサポート
        valid_issuers = [
            'https://login.brand1.com/',
            'https://login.brand2.com/',
            'https://login.example.com/'
        ]

        try:
            # カスタムドメインからJWKSを取得
            unverified = jwt.get_unverified_header(token)
            issuer = jwt.get_unverified_claims(token)['iss']

            if issuer not in valid_issuers:
                raise Exception('Invalid issuer')

            jwks_uri = f"{issuer}.well-known/jwks.json"
            jwks = requests.get(jwks_uri).json()

            payload = jwt.decode(
                token,
                jwks,
                algorithms=['RS256'],
                audience='YOUR_API_IDENTIFIER',
                issuer=valid_issuers
            )
        except Exception as e:
            return jsonify({'error': str(e)}), 401

        return f(*args, **kwargs)

    return decorated
```

<div id="java-spring-boot">
  ### Java (Spring Boot)
</div>

Spring Security を使用する場合:

```java theme={null}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${auth0.audience}")
    private String audience;

    @Value("${auth0.custom-domain}")
    private String customDomain;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .mvcMatchers("/api/public").permitAll()
            .mvcMatchers("/api/private").authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt()
            .decoder(jwtDecoder());
    }

    @Bean
    JwtDecoder jwtDecoder() {
        String issuerUri = "https://" + customDomain + "/";

        NimbusJwtDecoder jwtDecoder = JwtDecoders.fromIssuerLocation(issuerUri);

        // オーディエンスを検証
        OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
        OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
        OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);

        jwtDecoder.setJwtValidator(withAudience);

        return jwtDecoder;
    }
}
```

<div id="environment-specific-configuration">
  ## 環境ごとの設定
</div>

環境ごとにカスタムドメインを管理するには、環境変数を使用します。

<div id="env-file-structure">
  ### .env ファイルの構成
</div>

```bash theme={null}
# 開発環境
AUTH0_DOMAIN=dev.example.com
AUTH0_CLIENT_ID=dev_client_id
AUTH0_CLIENT_SECRET=dev_client_secret

# ステージング環境
# AUTH0_DOMAIN=staging.example.com
# AUTH0_CLIENT_ID=staging_client_id
# AUTH0_CLIENT_SECRET=staging_client_secret

# 本番環境
# AUTH0_DOMAIN=login.example.com
# AUTH0_CLIENT_ID=prod_client_id
# AUTH0_CLIENT_SECRET=prod_client_secret
```

<div id="loading-configuration">
  ### 設定の読み込み
</div>

```javascript theme={null}
require('dotenv').config();

const auth0Config = {
  domain: process.env.AUTH0_DOMAIN,
  clientId: process.env.AUTH0_CLIENT_ID,
  clientSecret: process.env.AUTH0_CLIENT_SECRET
};
```

<div id="troubleshooting">
  ## トラブルシューティング
</div>

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

<table class="table">
  <thead>
    <tr>
      <th><strong>問題</strong></th>
      <th><strong>原因</strong></th>
      <th><strong>解決策</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>発行元 が無効というエラー</td>
      <td>トークン検証では正規ドメインを想定していますが、実際にはカスタムドメインを受け取っています</td>
      <td>発行元 としてカスタムドメインを許可するようにトークン検証を更新します</td>
    </tr>

    <tr>
      <td>JWKS の取得に失敗する</td>
      <td>JWKS URI が正規ドメインを指しています</td>
      <td>JWKS URI がカスタムドメインを使用するように更新します: `https://custom-domain/.well-known/jwks.json`</td>
    </tr>

    <tr>
      <td>リダイレクト URI の不一致</td>
      <td>コールバック URL が設定されているリダイレクト URI と一致していません</td>
      <td>アプリケーション設定にカスタムドメインのコールバック URL を追加します</td>
    </tr>

    <tr>
      <td>クロスオリジン エラー (CORS) </td>
      <td>許可されたオリジンにカスタムドメインが含まれていません</td>
      <td>アプリケーション設定の Allowed Web Origins にカスタムドメインを追加します</td>
    </tr>

    <tr>
      <td>Lock の読み込みに失敗する</td>
      <td>`configurationBaseUrl` が設定されていません</td>
      <td>リージョン別 CDN URL を指定して `configurationBaseUrl` パラメーターを追加します</td>
    </tr>
  </tbody>
</table>

<div id="best-practices">
  ## ベストプラクティス
</div>

1. **環境変数を使用する**: カスタムドメインは環境ごとの設定ファイルに保存します
2. **複数の発行元を検証する**: 複数のカスタムドメインを使用する場合は、それらすべてを有効な発行元として受け入れるようにトークン検証を設定します
3. **コールバック URL を更新する**: すべてのカスタムドメインが、アプリケーション設定の Allowed Callback URLs に追加されていることを確認します
4. **十分にテストする**: 本番環境に移行する前に、各カスタムドメイン経由の認証をテストします
5. **トークンの発行元を監視する**: トークン内の `iss` クレームを記録して監視し、正しいカスタムドメインが使用されていることを確認します
6. **ドメインマッピングを文書化する**: どのアプリケーションがどのカスタムドメインを使用しているかを、明確に文書化して維持します
7. **障害を適切に処理する**: 認証の失敗に対する適切なエラーハンドリングを実装します
8. **JWKS をキャッシュする**: パフォーマンスを向上させ、リクエスト数を減らすために JWKS データをキャッシュします

<div id="learn-more">
  ## 詳細
</div>

* [複数のカスタムドメイン](/ja/docs/customize/custom-domains/multiple-custom-domains)
* [デフォルトのカスタムドメイン](/ja/docs/customize/custom-domains/multiple-custom-domains/default-domain)
* [機能でカスタムドメインを使用するよう設定する](/ja/docs/customize/custom-domains/configure-features-to-use-custom-domains)
* [Auth0 SDKs](/ja/docs/troubleshoot/customer-support/product-support-matrix#auth0-sdks)
