> ## 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 qu’ils fonctionnent 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) + "*****MASKED*****";
          }
          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](/fr-CA/docs/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 explique la configuration des SDK sur différentes plateformes et dans différents scénarios.

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

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

Tous les SDK Auth0 exigent 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 canonique Auth0.

**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é, la revendication `iss` (émetteur) des jetons est définie 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 afin d’accepter votre domaine personnalisé comme é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 les SDK pour résoudre les domaines personnalisés du locataire à l’aide des fonctions de résolution de domaine, vous devez vous assurer que tous les domaines résolus sont dignes de confiance. Une mauvaise configuration du résolveur de domaine peut permettre de contourner l’authentification auprès de la partie de confiance ou exposer l’application à une falsification de requêtes côté serveur. Si vos domaines et vos serveurs proxy ne sont pas configurés correctement, cela peut créer des vulnérabilités de sécurité critiques dont Okta ne peut être tenue responsable.
</Callout>

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

Pour les applications à page unique qui utilisent le [SDK Auth0 SPA](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 en fonction du contexte de l'application
  function getAuth0Domain() {
    const hostname = window.location.hostname;

    // Associe les domaines d'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 [SDK Next.js d’Auth0](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 }) => {
      // Associer 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';

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

    // Rechercher le domaine personnalisé pour ce locataire (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 (un seul locataire avec plusieurs domaines personnalisés)
  AUTH0_DOMAIN=login.example.com           # Domaine personnalisé par défaut ou de repli
  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 de MCD avec Next.js :**

* **Un seul locataire Auth0, plusieurs domaines** : Tous les domaines personnalisés partagent le même `clientId` et le même `clientSecret`, puisqu’ils appartiennent au même locataire Auth0.
* **Fonction DomainResolver** : Le paramètre `domain` accepte une fonction `(config: { headers: Headers; url?: URL }) => Promise<string> | string`. Cela permet de résoudre le domaine dynamiquement 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 borné (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 des sessions d’un autre domaine.
* **Paramètre URL** : Le paramètre `url` dans le résolveur vaut `undefined` dans les Server Components et les Server Actions; il est seulement disponible 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">
  ### SDK React d’Auth0
</div>

Pour les applications React utilisant le [SDK React d’Auth0](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 scénarios à plusieurs domaines :

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

Dans 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 locataire depuis le sous-domaine, le chemin ou l'en-tête
  const tenant = req.subdomains[0] || 'default';

  // Associer le locataire 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 pour appareils 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 le succès
        }

        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 la Management API d’Auth0. Si 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](/fr-CA/docs/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é sur toutes les requêtes sur liste blanche)
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 (point de terminaison sur liste blanche - l'en-tête est envoyé automatiquement)
const users = await management.users.getAll();

// Remplacement par requête (a la priorité sur le 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é pour toutes les requêtes sur liste blanche)
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 (point de terminaison sur liste blanche - 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 application : applique automatiquement l'en-tête de domaine personnalisé aux points de terminaison sur liste blanche
mgmt, err := management.New(
    "{yourDomain}",
    option.WithClientCredentials("{yourClientId}", "{yourClientSecret}"),
    option.WithCustomDomainHeader("login.example.com"),
)
if err != nil {
    // Gérer l'erreur
}

// Lister les utilisateurs (point de terminaison sur liste blanche - 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 application)
userList, err := mgmt.Users.List(
    context.Background(),
    nil,
    option.WithCustomDomainHeader("specific-request.exampleco.com"),
)
```

<div id="token-validation">
  ## Validation du jeton
</div>

Lorsque vous utilisez des domaines personnalisés, mettez à jour la validation de votre jeton pour qu'elle accepte 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>

À l’aide de [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()

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

        try:
            # Obtenir 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 selon l’environnement :

<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 invalide</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 du JWKS pointe vers le domaine canonique</td>
      <td>Mettez à jour l’URI du JWKS pour utiliser le domaine personnalisé : `https://custom-domain/.well-known/jwks.json`</td>
    </tr>

    <tr>
      <td>URI de redirection non concordante</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 d’origine croisée (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>Le paramètre `configurationBaseUrl` est absent</td>
      <td>Ajoutez le paramètre `configurationBaseUrl` avec l’URL du CDN régional</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 les accepter tous comme émetteurs valides
3. **Mettez à jour les URL de rappel** : assurez-vous que tous les domaines personnalisés sont ajoutés à Allowed Callback URLs dans les paramètres de l’application
4. **Testez de façon approfondie** : testez l’authentification avec chaque domaine personnalisé avant la mise en production
5. **Surveillez les émetteurs de jetons** : consignez et surveillez la revendication `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 correctement les échecs** : implémentez une gestion des erreurs appropriée pour les échecs d’authentification
8. **Mettez en cache JWKS** : mettez en cache les données JWKS pour améliorer les performances et réduire le nombre de requêtes

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

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