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

> Découvrez comment configurer les SDK Auth0 pour fonctionner avec plusieurs domaines personnalisés.

# Configuration des SDK pour plusieurs domaines personnalisés

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) + "*****MASQUÉ*****";
          }
          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>;
};

Lorsque vous utilisez [plusieurs domaines personnalisés](/docs/fr-ca/customize/custom-domains/multiple-custom-domains), vous devez configurer vos SDK Auth0 pour qu’ils utilisent le domaine personnalisé approprié pour l’authentification. Ce guide présente la configuration des SDK pour différentes plateformes et divers scénarios.

<div id="key-concepts">
  ## Concepts clés
</div>

<div id="domain-parameter">
  ### Paramètre de domaine
</div>

Tous les SDK Auth0 nécessitent un paramètre `domain` qui indique quel domaine Auth0 utiliser pour l’authentification. Si vous utilisez des domaines personnalisés, définissez ce paramètre sur votre domaine personnalisé plutôt que sur votre domaine Auth0 canonique.

**Sans domaine personnalisé :**

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

**Avec un domaine personnalisé :**

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

<div id="token-issuer">
  ### Émetteur du jeton
</div>

Lorsque vous utilisez un domaine personnalisé, les jetons auront le champ `iss` (issuer) défini sur votre domaine personnalisé :

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

Vous devez configurer la validation du jeton pour qu’elle reconnaisse votre domaine personnalisé comme un émetteur valide.

<div id="authentication-sdks">
  ## SDK d’authentification
</div>

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Lorsque vous utilisez MCD, le client est responsable de fournir et de valider tous les domaines personnalisés. Lorsque vous configurez des SDK pour résoudre les domaines personnalisés du tenant au moyen des fonctions de résolution de domaine, il vous incombe de vous assurer que tous les domaines résolus sont fiables. Une mauvaise configuration du résolveur de domaine peut permettre de contourner l’authentification du côté de la partie de confiance ou exposer l’application à une attaque de falsification de requêtes côté serveur. Si vos domaines et vos serveurs proxy ne sont pas correctement configurés, cela peut entraîner des vulnérabilités de sécurité critiques dont Okta ne peut être tenue responsable.
</Callout>

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

Pour les applications monopage utilisant le [Auth0 SPA SDK](https://github.com/auth0/auth0-spa-js) :

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

  const auth0 = await createAuth0Client({
    domain: 'login.example.com',  // Votre domaine personnalisé
    clientId: 'YOUR_CLIENT_ID',
    authorizationParams: {
      redirect_uri: window.location.origin
    }
  });
  ```

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

  // Détermine le domaine selon le contexte de l’application
  function getAuth0Domain() {
    const hostname = window.location.hostname;

    // Associe les domaines de l’application aux domaines personnalisés Auth0
    if (hostname.includes('app1.example.com')) {
      return 'login.brand1.com';
    } else if (hostname.includes('app2.example.com')) {
      return 'login.brand2.com';
    }

    // Domaine personnalisé par défaut
    return 'login.example.com';
  }

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

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

  const auth0 = await createAuth0Client({
    domain: process.env.REACT_APP_AUTH0_DOMAIN,  // À partir du fichier .env
    clientId: process.env.REACT_APP_AUTH0_CLIENT_ID,
    authorizationParams: {
      redirect_uri: window.location.origin
    }
  });
  ```
</AuthCodeGroup>

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

Pour les applications Next.js qui utilisent le [Auth0 Next.js SDK](https://github.com/auth0/nextjs-auth0) (v4+) :

<AuthCodeGroup>
  ```typescript Configuration statique theme={null}
  import { Auth0Client } from '@auth0/nextjs-auth0/server';

  const auth0 = new Auth0Client({
    domain: 'login.example.com',        // Votre domaine personnalisé
    clientId: process.env.AUTH0_CLIENT_ID,
    clientSecret: process.env.AUTH0_CLIENT_SECRET,
    appBaseUrl: process.env.APP_BASE_URL,
    secret: process.env.AUTH0_SECRET
  });
  ```

  ```typescript Configuration dynamique (multimarque) theme={null}
  import { Auth0Client } from '@auth0/nextjs-auth0/server';

  const auth0 = new Auth0Client({
    domain: ({ headers }) => {
      // Mapper les hôtes d’application aux domaines personnalisés 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';  // Domaine par défaut
    },
    clientId: process.env.AUTH0_CLIENT_ID,
    clientSecret: process.env.AUTH0_CLIENT_SECRET,
    appBaseUrl: process.env.APP_BASE_URL,
    secret: process.env.AUTH0_SECRET
  });
  ```

  ```typescript Configuration dynamique (SaaS B2B) theme={null}
  import { Auth0Client } from '@auth0/nextjs-auth0/server';

  // Mapper les identifiants de tenant aux domaines personnalisés (à partir de la base de données, du cache, etc.)
  async function resolveTenantDomain(host: string): Promise<string> {
    // Extraire l’identifiant du tenant à partir du sous-domaine
    const subdomain = host.split('.')[0];

    // Rechercher le domaine personnalisé pour ce tenant (par exemple, dans la base de données)
    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 Variables d’environnement theme={null}
  # .env.local

  # Configuration Auth0 (tenant unique avec plusieurs domaines personnalisés)
  AUTH0_DOMAIN=login.example.com           # Domaine personnalisé par défaut ou domaine de secours
  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>

**Concepts clés pour MCD avec Next.js :**

* **Un seul tenant Auth0, plusieurs domaines** : Tous les domaines personnalisés partagent le même `clientId` et le même `clientSecret`, puisqu’ils appartiennent au même tenant Auth0.
* **Fonction DomainResolver** : Le paramètre `domain` accepte une fonction `(config: { headers: Headers; url?: URL }) => Promise<string> | string`. Cela permet de résoudre dynamiquement le domaine pour chaque requête selon les en-têtes de la requête entrante.
* **Mise en cache des instances** : Le SDK met automatiquement en cache les instances `Auth0Client` par domaine au moyen d’un cache LRU de taille limitée (maximum de 100 entrées) afin d’améliorer les performances.
* **Isolation des sessions** : Les sessions créées au moyen d’un domaine personnalisé sont isolées à ce domaine et ne peuvent pas être utilisées de façon interchangeable avec les sessions d’un autre domaine.
* **Paramètre d’URL** : Le paramètre `url` dans le résolveur est `undefined` dans les composants serveur et les Actions serveur; il n’est disponible que dans le middleware ou les routes d’API.
* **Ajustement du cache de découverte** : Configurez la mise en cache des métadonnées OIDC avec l’option `discoveryCache` :
  ```typescript theme={null}
  const auth0 = new Auth0Client({
    // ... autre configuration
    discoveryCache: {
      ttl: 600,      // Mettre en cache pendant 10 minutes (par défaut)
      maxEntries: 100  // Nombre maximal d’émetteurs mis en cache (par défaut : 100, éviction LRU)
    }
  });
  ```

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

Pour les applications React qui utilisent le [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>
  );
}
```

Dans les cas où plusieurs domaines sont utilisés :

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

function App() {
  // Déterminer le domaine personnalisé selon l'environnement ou le contexte
  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>

Pour les applications qui utilisent [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'
});

// Initier la connexion
webAuth.authorize();
```

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

Pour les applications Node.js qui utilisent [express-openid-connect](https://github.com/auth0/express-openid-connect) :

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

app.use(
  auth({
    authRequired: false,
    auth0Logout: true,
    issuerBaseURL: 'https://login.example.com',  // Votre domaine personnalisé
    baseURL: 'http://localhost:3000',
    clientID: 'YOUR_CLIENT_ID',
    secret: 'YOUR_CLIENT_SECRET'
  })
);
```

Pour les scénarios multilocataires :

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

// Middleware pour déterminer le domaine personnalisé par requête
app.use((req, res, next) => {
  // Extraire l'identifiant du tenant depuis le sous-domaine, le chemin ou l'en-tête
  const tenant = req.subdomains[0] || 'default';

  // Mapper le tenant au domaine personnalisé
  const domainMap = {
    'customer1': 'login.customer1.com',
    'customer2': 'login.customer2.com',
    'default': 'login.example.com'
  };

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

// Configuration d'authentification dynamique
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 mobiles
</div>

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

Avec [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)")
        }
    }
```

Pour sélectionner le domaine dynamiquement :

```swift theme={null}
import Auth0

class AuthService {
    private let clientId = "YOUR_CLIENT_ID"

    func getAuth0Domain() -> String {
        // Déterminer le domaine en fonction de la configuration de l'application
        if let savedDomain = UserDefaults.standard.string(forKey: "auth0Domain") {
            return savedDomain
        }
        return "login.example.com" // Par défaut
    }

    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>

Avec [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"  // Votre domaine personnalisé
)

WebAuthProvider.login(account)
    .withScheme("demo")
    .withScope("openid profile email")
    .start(this, object : Callback<Credentials, AuthenticationException> {
        override fun onSuccess(credentials: Credentials) {
            // Gérer la réussite
        }

        override fun onFailure(exception: AuthenticationException) {
            // Gérer l'échec
        }
    })
```

Pour prendre en charge plusieurs domaines :

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

    private fun getAuth0Domain(): String {
        // Récupérer depuis les préférences partagées ou la configuration de l'app
        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>

Avec [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'
});

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

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

Avec [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'
);

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

<div id="management-sdks">
  ## SDK de gestion
</div>

Les SDK de gestion permettent d’interagir avec Auth0 Management API. Lorsque vous utilisez des domaines personnalisés, vous devrez peut-être inclure l’en-tête `auth0-custom-domain` ou utiliser le [domaine par défaut](/docs/fr-ca/customize/custom-domains/multiple-custom-domains/default-domain).

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

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

// Domaine personnalisé global (envoyé pour toutes les requêtes whitelisted)
const management = new ManagementClient({
  domain: 'tenant.auth0.com',
  clientId: 'YOUR_M2M_CLIENT_ID',
  clientSecret: 'YOUR_M2M_CLIENT_SECRET',
  withCustomDomainHeader: 'login.example.com', 
});

// Lister les utilisateurs (endpoint whitelisted - l'en-tête est envoyé automatiquement)
const users = await management.users.getAll();

// Remplacement par requête (a la priorité sur le paramètre global)
const reqOptions = {
  ...CustomDomainHeader("specific-user-request.exampleco.com"),
};
const response = await management.users.getAll({}, reqOptions);
```

<div id="python-management-sdk">
  ### SDK de gestion pour Python
</div>

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

# Domaine personnalisé global (envoyé sur toutes les requêtes whitelisted)
client = ManagementClient(
    domain='tenant.auth0.com',
    client_id='YOUR_M2M_CLIENT_ID',
    client_secret='YOUR_M2M_CLIENT_SECRET',
    custom_domain='login.example.com',
)

# Lister les utilisateurs (endpoint whitelisted - l'en-tête est envoyé automatiquement)
users = client.users.list()

# Remplacement par requête (a la priorité sur le global)
client.users.create(
    connection='Username-Password-Authentication',
    email='user@example.com',
    password='SecurePass123!',
    request_options=CustomDomainHeader('login.brand2.com'),
)
```

<div id="go-management-sdk">
  ### SDK de gestion pour Go
</div>

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

// Niveau client : applique automatiquement l'en-tête de domaine personnalisé aux endpoints whitelisted
mgmt, err := management.New(
    "{yourDomain}",
    option.WithClientCredentials("{yourClientId}", "{yourClientSecret}"),
    option.WithCustomDomainHeader("login.example.com"),
)
if err != nil {
    // Gérer l'erreur
}

// Lister les utilisateurs (endpoint whitelisted - l'en-tête est envoyé automatiquement)
userList, err := mgmt.Users.List(context.Background(), nil)

// Remplacement par requête (a la priorité sur le niveau client)
userList, err := mgmt.Users.List(
    context.Background(),
    nil,
    option.WithCustomDomainHeader("specific-request.exampleco.com"),
)
```

<div id="token-validation">
  ## Validation des jetons
</div>

Lorsque vous utilisez des domaines personnalisés, mettez à jour la validation de vos jetons pour accepter le domaine personnalisé comme émetteur.

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

Avec [express-jwt](https://github.com/auth0/express-jwt) ou [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'  // Domaine personnalisé
    }),
    audience: 'YOUR_API_IDENTIFIER',
    issuer: 'https://login.example.com/',  // Domaine personnalisé en tant qu'émetteur
    algorithms: ['RS256']
  })
);
```

Pour plusieurs domaines personnalisés :

```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) => {
        // Extraire l'émetteur du jeton pour déterminer l'URI JWKS
        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,  // Accepter plusieurs émetteurs
    algorithms: ['RS256']
  })
);
```

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

Avec [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()

        # Prise en charge de plusieurs domaines personnalisés
        valid_issuers = [
            'https://login.brand1.com/',
            'https://login.brand2.com/',
            'https://login.example.com/'
        ]

        try:
            # Récupérer le JWKS depuis le domaine personnalisé
            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>

Avec 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);

        // Valider l'audience
        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">
  ## Configuration propre à chaque environnement
</div>

Utilisez des variables d’environnement pour gérer les domaines personnalisés d’un environnement à l’autre :

<div id="env-file-structure">
  ### Structure du fichier .env
</div>

```bash theme={null}
# Développement
AUTH0_DOMAIN=dev.example.com
AUTH0_CLIENT_ID=dev_client_id
AUTH0_CLIENT_SECRET=dev_client_secret

# Préproduction
# AUTH0_DOMAIN=staging.example.com
# AUTH0_CLIENT_ID=staging_client_id
# AUTH0_CLIENT_SECRET=staging_client_secret

# Production
# AUTH0_DOMAIN=login.example.com
# AUTH0_CLIENT_ID=prod_client_id
# AUTH0_CLIENT_SECRET=prod_client_secret
```

<div id="loading-configuration">
  ### Chargement de la 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">
  ## Dépannage
</div>

<div id="common-issues">
  ### Problèmes courants
</div>

<table class="table">
  <thead>
    <tr>
      <th><strong>Problème</strong></th>
      <th><strong>Cause</strong></th>
      <th><strong>Solution</strong></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Erreur d’émetteur non valide</td>
      <td>La validation du jeton s’attend au domaine canonique, mais reçoit un domaine personnalisé</td>
      <td>Mettez à jour la validation du jeton pour accepter le domaine personnalisé comme émetteur</td>
    </tr>

    <tr>
      <td>Échec de la récupération du JWKS</td>
      <td>L’URI JWKS pointe vers le domaine canonique</td>
      <td>Mettez à jour l’URI JWKS pour utiliser le domaine personnalisé : `https://custom-domain/.well-known/jwks.json`</td>
    </tr>

    <tr>
      <td>Non-correspondance de l’URI de redirection</td>
      <td>L’URL de rappel ne correspond pas aux URI de redirection configurées</td>
      <td>Ajoutez l’URL de rappel du domaine personnalisé aux paramètres de l’application</td>
    </tr>

    <tr>
      <td>Erreurs inter-origines (CORS)</td>
      <td>Le domaine personnalisé ne figure pas parmi les origines autorisées</td>
      <td>Ajoutez le domaine personnalisé à Allowed Web Origins dans les paramètres de l’application</td>
    </tr>

    <tr>
      <td>Échec du chargement de Lock</td>
      <td>`configurationBaseUrl` est manquant</td>
      <td>Ajoutez le paramètre `configurationBaseUrl` avec l’URL régionale du CDN</td>
    </tr>
  </tbody>
</table>

<div id="best-practices">
  ## Bonnes pratiques
</div>

1. **Utilisez des variables d'environnement** : stockez les domaines personnalisés dans des fichiers de configuration propres à chaque environnement
2. **Validez plusieurs émetteurs** : si vous utilisez plusieurs domaines personnalisés, configurez la validation des jetons pour accepter tous les émetteurs valides
3. **Mettez à jour les URL de rappel** : assurez-vous que tous les domaines personnalisés sont ajoutés aux Allowed Callback URLs dans les paramètres de l'application
4. **Testez de façon approfondie** : testez l'authentification avec chaque domaine personnalisé avant le déploiement en production
5. **Surveillez les émetteurs des jetons** : consignez et surveillez le claim `iss` dans les jetons pour vous assurer que le bon domaine personnalisé est utilisé
6. **Documentez les mappages de domaines** : tenez à jour une documentation claire indiquant quelles applications utilisent quels domaines personnalisés
7. **Gérez bien les échecs** : mettez en place une gestion adéquate des erreurs en cas d'échec d'authentification
8. **Mettez JWKS en cache** : mettez en cache les données JWKS pour améliorer les performances et réduire les requêtes

<div id="learn-more">
  ## En savoir plus
</div>

* [Plusieurs domaines personnalisés](/docs/fr-ca/customize/custom-domains/multiple-custom-domains)
* [Domaine personnalisé par défaut](/docs/fr-ca/customize/custom-domains/multiple-custom-domains/default-domain)
* [Configurer les fonctionnalités pour utiliser des domaines personnalisés](/docs/fr-ca/customize/custom-domains/configure-features-to-use-custom-domains)
* [SDK Auth0](/docs/fr-ca/troubleshoot/customer-support/product-support-matrix#auth0-sdks)
