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

> Ce guide montre comment ajouter la connexion des utilisateurs à une application web Go à l’aide du SDK go-auth0.

# Ajouter la connexion à votre application Go

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

export const CreateInteractiveApp = ({placeholderText = "Auth0", appType = "regular_web", allowedCallbackUrls = ["localhost:3000"], allowedLogoutUrls = ["localhost:3000"], allowedOriginUrls = ["localhost:3000"]}) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [storeReady, setStoreReady] = useState(false);
  const [displayForm, setDisplayForm] = useState(true);
  useEffect(() => {
    const init = () => setStoreReady(true);
    if (window.rootStore) {
      window.rootStore.clientStore.setSelectedClient(null);
      window.rootStore.clientStore.setSelectedClientSecret(undefined);
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
    };
  }, []);
  useEffect(() => {
    if (!storeReady) return;
    const disposer = autorun(() => {
      const rootStore = window.rootStore;
      setIsAuthenticated(rootStore.sessionStore.isAuthenticated);
    });
    return () => {
      disposer();
    };
  }, [storeReady]);
  if (!storeReady || typeof window === "undefined" || !displayForm) {
    return <></>;
  }
  const login = () => {
    const baseUrl = window.rootStore.config.apiBaseUrl;
    const returnTo = encodeURIComponent(window.location.href);
    window.location.href = `${baseUrl}/auth/user/login?returnTo=${returnTo}`;
  };
  const Card = ({className = "", children}) => {
    return <div className={`
          flex border rounded-2xl
          border-gray-950/10 dark:border-white/10
          py-3.5 px-4 gap-2
          text-sm text-gray-900 dark:text-gray-200
          ${className}
        `}>
        {children}
      </div>;
  };
  const Button = ({children, ...props}) => {
    return <button className="bg-[--button-primary] text-[--foreground-inverse] px-[1.125rem] py-1.5 rounded-lg font-medium" {...props}>
        {children}
      </button>;
  };
  const CreateApplicationForm = () => {
    const [name, setName] = useState("");
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState("");
    const handleSubmit = async () => {
      if (!name.trim()) {
        setError("Le nom de l'application est requis");
        return;
      }
      setIsLoading(true);
      setError(null);
      try {
        await window.rootStore.clientStore.createClient({
          name: name.trim(),
          app_type: appType,
          callbacks: allowedCallbackUrls,
          allowed_logout_urls: allowedLogoutUrls,
          web_origins: allowedOriginUrls,
          client_metadata: {
            created_by: "quickstart-docs-app-creation-component"
          }
        });
        setDisplayForm(false);
      } catch (err) {
        console.error("Erreur lors de la création de l'application :", err);
        const errorMessage = err instanceof Error ? err.message : "Échec de la création de l'application";
        setError(errorMessage);
      } finally {
        setIsLoading(false);
      }
    };
    return <Card className="flex-col items-start p-4 gap-3.75">
        <span className="font-medium text-gray-900 dark:text-gray-200">Créer une application Auth0</span>
        <div className="w-full flex gap-2">
          <input id="app-name" name={name} className="
              w-full max-w-[448px] h-11 py-2 px-4 
              border rounded-lg border-gray-950/10 dark:border-white/10 
              text-gray-900 dark:text-gray-200
              focus:outline-none dark:focus:outline-none
            " placeholder={`Mon application ${placeholderText}`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>{isLoading ? "Création en cours..." : "Créer"}</Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>Se connecter</Button> <span>pour créer l'application</span>
      </Card>;
  };
  return isAuthenticated ? <CreateApplicationForm /> : <SignInForm />;
};

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

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

<Note>
  **Prérequis :** Avant de commencer, assurez-vous d’avoir installé les éléments suivants :

  * **[Go](https://go.dev/doc/install)** 1.25 ou une version ultérieure
  * **[Git](https://git-scm.com/downloads)** pour la gestion de versions

  Vérifiez l’installation : `go version`
</Note>

<div id="get-started">
  ## Pour commencer
</div>

Ce guide de démarrage rapide montre comment ajouter l’authentification Auth0 à une application Web en Go. Vous créerez une application côté serveur avec des fonctionnalités de connexion, de déconnexion et de profil utilisateur à l’aide du SDK [go-auth0](https://github.com/auth0/go-auth0) et de la bibliothèque standard `net/http` de Go.

export const localEnvSnippet = `# L’URL du domaine de votre locataire Auth0.
# Si vous utilisez un domaine personnalisé, utilisez cette valeur à la place.
AUTH0_DOMAIN={yourDomain}

# L’ID client de votre application Auth0.
AUTH0_CLIENT_ID={yourClientId}

# Le Secret client de votre application Auth0.
AUTH0_CLIENT_SECRET={yourClientSecret}

# L’URL de rappel de votre application.
AUTH0_CALLBACK_URL=http://localhost:3000/callback

# Une longue clé secrète aléatoire utilisée pour chiffrer les témoins de session.
SESSION_SECRET=a-long-random-secret-key-for-cookie-encryption`;

<Steps>
  <Step title="Créer un projet" stepNumber={1}>
    Créez un nouveau répertoire pour votre application Go, puis initialisez un module.

    ```shellscript theme={null}
    mkdir myapp && cd myapp
    go mod init myapp
    ```

    Installez les dépendances requises :

    ```shellscript theme={null}
    go get github.com/auth0/go-auth0/v2
    go get github.com/gorilla/sessions
    go get github.com/joho/godotenv
    ```

    Créez la structure du projet :

    ```shellscript theme={null}
    mkdir templates
    touch .env auth.go handlers.go main.go templates/home.html templates/user.html
    ```

    <Accordion title="Voir le fichier go.mod attendu">
      ```go go.mod theme={null}
      module myapp

      go 1.25

      require (
          github.com/auth0/go-auth0/v2 v2.10.0
          github.com/gorilla/sessions v1.4.0
          github.com/joho/godotenv v1.5.1
      )
      ```
    </Accordion>
  </Step>

  <Step title="Configurez votre application Auth0" stepNumber={2}>
    Pour utiliser les services Auth0, vous devez d’abord configurer une application dans l’Auth0 Dashboard. C’est dans cette application Auth0 que vous configurez l’authentification pour votre projet.

    Vous aurez besoin des renseignements suivants dans l’onglet **Settings** de votre application :

    * **Domaine**
    * **ID client**
    * **Secret client**

    <Frame>![Tableau de bord de l’application](https://cdn2.auth0.com/docs/1.14550.0/media/articles/dashboard/client_settings.png)</Frame>

    Vous avez trois options pour configurer votre application Auth0 : utiliser l’outil Quick Setup (recommandé), exécuter une commande CLI ou faire la configuration manuellement dans l’Auth0 Dashboard :

    <Tabs>
      <Tab title="Quick Setup (recommandé)">
        Créez une application Auth0 et copiez le fichier `.env` prérempli avec les bonnes valeurs de configuration.

        <CreateInteractiveApp placeholderText="Go" appType="regular_web" allowedCallbackUrls={["http://localhost:3000/callback"]} allowedLogoutUrls={["http://localhost:3000"]} />

        <AuthCodeBlock children={localEnvSnippet} language="shellscript" filename=".env" />
      </Tab>

      <Tab title="CLI">
        Exécutez la commande suivante à la racine de votre projet pour créer une application Auth0 :

        <CodeGroup>
          ```shellscript Mac theme={null}
          # Installer Auth0 CLI (si ce n'est pas déjà fait)
          brew tap auth0/auth0-cli && brew install auth0

          # Créer une application Auth0
          auth0 apps create \
            --name "My Go App" \
            --type regular \
            --callbacks http://localhost:3000/callback \
            --logout-urls http://localhost:3000
          ```

          ```powershell Windows theme={null}
          # Installer Auth0 CLI (si ce n'est pas déjà fait)
          scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
          scoop install auth0

          # Créer une application Auth0
          auth0 apps create `
            --name "My Go App" `
            --type regular `
            --callbacks http://localhost:3000/callback `
            --logout-urls http://localhost:3000
          ```
        </CodeGroup>

        Une fois l’application créée, copiez les valeurs **Domaine**, **ID client** et **Secret client**, puis créez votre fichier `.env` :

        <AuthCodeBlock children={localEnvSnippet} language="shellscript" filename=".env" />

        <Note>
          Cette commande effectue les actions suivantes :

          1. Vérifie si vous êtes authentifié (et vous invite à vous connecter au besoin)
          2. Crée une application Web régulière Auth0 configurée pour `http://localhost:3000`
          3. Affiche les détails de l’application, y compris le domaine, l’ID client et le secret client
        </Note>
      </Tab>

      <Tab title="Auth0 Dashboard">
        1. Accédez à l’[Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Cliquez sur **Applications** > **Applications** > **Create Application**
        3. Dans la fenêtre contextuelle, saisissez un nom pour votre application, sélectionnez `Regular Web Applications` comme type d’application, puis cliquez sur **Create**
        4. Ouvrez l’onglet **Settings** dans la page des détails de l’application
        5. Prenez en note les valeurs **Domaine**, **ID client** et **Secret client**

        ### Configurer les URL de rappel

        Une URL de rappel est l’URL de votre application vers laquelle Auth0 redirige l’utilisateur après son authentification. Si elle n’est pas définie, les utilisateurs ne seront pas redirigés vers votre application après la connexion.

        Définissez **Allowed Callback URLs** sur :

        ```
        http://localhost:3000/callback
        ```

        ### Configurer les URL de déconnexion

        Une URL de déconnexion est l’URL de votre application vers laquelle Auth0 peut rediriger l’utilisateur après sa déconnexion. Si elle n’est pas définie, les utilisateurs ne pourront pas se déconnecter de votre application et recevront une erreur.

        Définissez **Allowed Logout URLs** sur :

        ```
        http://localhost:3000
        ```

        ### Créer votre fichier d’environnement

        Créez un fichier `.env` à la racine de votre projet avec les valeurs de l’Auth0 Dashboard :

        ```shellscript .env theme={null}
        AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
        AUTH0_CLIENT_ID=YOUR_AUTH0_CLIENT_ID
        AUTH0_CLIENT_SECRET=YOUR_AUTH0_CLIENT_SECRET
        AUTH0_CALLBACK_URL=http://localhost:3000/callback
        SESSION_SECRET=a-long-random-secret-key-for-cookie-encryption
        ```

        <Warning>
          Remplacez `YOUR_AUTH0_DOMAIN`, `YOUR_AUTH0_CLIENT_ID` et `YOUR_AUTH0_CLIENT_SECRET` par les valeurs réelles indiquées dans l’onglet Settings de votre application.
        </Warning>
      </Tab>
    </Tabs>

    <Tip>
      Vérifiez que votre fichier `.env` existe : `cat .env` (Mac/Linux) ou `type .env` (Windows)
    </Tip>
  </Step>

  <Step title="Créer l’application Auth0" stepNumber={3}>
    Créez le fichier `auth.go`. Il encapsule le client d’authentification `go-auth0` et fournit une fonction utilitaire pour générer l’URL d’autorisation.

    ```go auth.go lines theme={null}
    package main

    import (
        "context"
        "fmt"
        "net/url"
        "os"

        "github.com/auth0/go-auth0/v2/authentication"
    )

    // Authenticator encapsule le client d'authentification go-auth0.
    type Authenticator struct {
        *authentication.Authentication
        Domain      string
        ClientID    string
        CallbackURL string
    }

    // NewAuthenticator crée et configure un nouvel Authenticator.
    func NewAuthenticator() (*Authenticator, error) {
        domain := os.Getenv("AUTH0_DOMAIN")
        clientID := os.Getenv("AUTH0_CLIENT_ID")
        clientSecret := os.Getenv("AUTH0_CLIENT_SECRET")
        callbackURL := os.Getenv("AUTH0_CALLBACK_URL")

        authClient, err := authentication.New(
            context.Background(),
            domain,
            authentication.WithClientID(clientID),
            authentication.WithClientSecret(clientSecret),
        )
        if err != nil {
            return nil, fmt.Errorf("failed to initialize authentication client: %w", err)
        }

        return &Authenticator{
            Authentication: authClient,
            Domain:         domain,
            ClientID:       clientID,
            CallbackURL:    callbackURL,
        }, nil
    }

    // AuthorizationURL construit l'URL /authorize pour rediriger les utilisateurs
    // vers la page Universal Login d'Auth0.
    func (a *Authenticator) AuthorizationURL(state string) string {
        u, _ := url.Parse("https://" + a.Domain + "/authorize")
        params := url.Values{
            "response_type": {"code"},
            "client_id":     {a.ClientID},
            "redirect_uri":  {a.CallbackURL},
            "scope":         {"openid profile email"},
            "state":         {state},
        }
        u.RawQuery = params.Encode()
        return u.String()
    }
    ```

    **Ce que cela fait :**

    * Initialise le client d’authentification `go-auth0` avec le domaine de votre locataire, l’ID client et le secret client
    * Fournit un utilitaire `AuthorizationURL` qui génère l’URL de redirection `/authorize` avec les paramètres OAuth2 requis
  </Step>

  <Step title="Créer des gestionnaires de routes" stepNumber={4}>
    Créez le fichier `handlers.go` avec des gestionnaires pour la connexion, le rappel, le profil utilisateur et la déconnexion.

    ```go handlers.go expandable lines theme={null}
    package main

    import (
        "crypto/rand"
        "encoding/base64"
        "encoding/gob"
        "net/http"
        "net/url"
        "os"

        "github.com/auth0/go-auth0/v2/authentication/oauth"
        "github.com/gorilla/sessions"
    )

    var store *sessions.CookieStore

    func init() {
        gob.Register(map[string]interface{}{})
    }

    func initSessionStore() {
        store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_SECRET")))
        store.Options = &sessions.Options{
            Path:     "/",
            MaxAge:   86400,
            HttpOnly: true,
            Secure:   false, // Définir à true en production (nécessite HTTPS)
            SameSite: http.SameSiteLaxMode,
        }
    }

    // HomeHandler affiche la page d'accueil ou redirige vers /user si l'utilisateur est déjà connecté.
    func HomeHandler(w http.ResponseWriter, r *http.Request) {
        session, _ := store.Get(r, "auth-session")
        if session.Values["profile"] != nil {
            http.Redirect(w, r, "/user", http.StatusSeeOther)
            return
        }
        if err := templates.ExecuteTemplate(w, "home.html", nil); err != nil {
            http.Error(w, "Internal error", http.StatusInternalServerError)
        }
    }

    // LoginHandler redirige l'utilisateur vers la page Universal Login d'Auth0.
    func LoginHandler(auth *Authenticator) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            state, err := generateRandomState()
            if err != nil {
                http.Error(w, "Internal error", http.StatusInternalServerError)
                return
            }

            session, _ := store.Get(r, "auth-session")
            session.Values["state"] = state
            if err := session.Save(r, w); err != nil {
                http.Error(w, "Internal error", http.StatusInternalServerError)
                return
            }

            http.Redirect(w, r, auth.AuthorizationURL(state), http.StatusTemporaryRedirect)
        }
    }

    // CallbackHandler gère le rappel d'Auth0 après l'authentification.
    func CallbackHandler(auth *Authenticator) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            session, _ := store.Get(r, "auth-session")

            // Vérifier le paramètre state pour prévenir les attaques CSRF.
            if r.URL.Query().Get("state") != session.Values["state"] {
                http.Error(w, "Invalid state parameter", http.StatusBadRequest)
                return
            }

            // Échanger le code d'autorisation contre des jetons.
            tokenSet, err := auth.OAuth.LoginWithAuthCode(r.Context(), oauth.LoginWithAuthCodeRequest{
                Code:        r.URL.Query().Get("code"),
                RedirectURI: auth.CallbackURL,
            }, oauth.IDTokenValidationOptions{})
            if err != nil {
                http.Error(w, "Failed to exchange authorization code for token", http.StatusUnauthorized)
                return
            }

            // Récupérer les informations de profil de l'utilisateur.
            userInfo, err := auth.UserInfo(r.Context(), tokenSet.AccessToken)
            if err != nil {
                http.Error(w, "Failed to get user info", http.StatusInternalServerError)
                return
            }

            session.Values["access_token"] = tokenSet.AccessToken
            session.Values["profile"] = map[string]interface{}{
                "nickname": userInfo.Nickname,
                "name":     userInfo.Name,
                "picture":  userInfo.Picture,
                "email":    userInfo.Email,
            }
            if err := session.Save(r, w); err != nil {
                http.Error(w, "Internal error", http.StatusInternalServerError)
                return
            }

            http.Redirect(w, r, "/user", http.StatusTemporaryRedirect)
        }
    }

    // UserHandler affiche le profil de l'utilisateur authentifié.
    func UserHandler(w http.ResponseWriter, r *http.Request) {
        session, _ := store.Get(r, "auth-session")
        profile, ok := session.Values["profile"].(map[string]interface{})
        if !ok {
            http.Redirect(w, r, "/", http.StatusSeeOther)
            return
        }

        if err := templates.ExecuteTemplate(w, "user.html", profile); err != nil {
            http.Error(w, "Internal error", http.StatusInternalServerError)
        }
    }

    // LogoutHandler efface la session et redirige vers le point de terminaison de déconnexion d'Auth0.
    func LogoutHandler(auth *Authenticator) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            session, _ := store.Get(r, "auth-session")
            session.Options.MaxAge = -1
            session.Save(r, w)

            logoutURL, _ := url.Parse("https://" + auth.Domain + "/v2/logout")
            scheme := "http"
            if r.TLS != nil {
                scheme = "https"
            }

            returnTo, _ := url.Parse(scheme + "://" + r.Host)
            params := url.Values{}
            params.Add("returnTo", returnTo.String())
            params.Add("client_id", auth.ClientID)
            logoutURL.RawQuery = params.Encode()

            http.Redirect(w, r, logoutURL.String(), http.StatusTemporaryRedirect)
        }
    }

    func generateRandomState() (string, error) {
        b := make([]byte, 32)
        _, err := rand.Read(b)
        if err != nil {
            return "", err
        }
        return base64.RawURLEncoding.EncodeToString(b), nil
    }
    ```

    **Points clés :**

    * **LoginHandler** génère un paramètre state aléatoire pour se protéger contre les attaques CSRF et redirige vers l’Universal Login d’Auth0
    * **CallbackHandler** échange le code d’autorisation contre des jetons au moyen de `go-auth0`, puis appelle `UserInfo` pour obtenir le profil de l’utilisateur
    * **LogoutHandler** supprime la session et redirige vers le point de terminaison `/v2/logout` d’Auth0
    * **UserHandler** récupère le profil de la session et effectue le rendu du gabarit
  </Step>

  <Step title="Créer des gabarits HTML" stepNumber={5}>
    <Tabs>
      <Tab title="home.html">
        ```html templates/home.html expandable lines theme={null}
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Auth0 Go Web App</title>
            <style>
                * { margin: 0; padding: 0; box-sizing: border-box; }
                body {
                    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                    background: #0a0a0a;
                    color: #e2e8f0;
                    min-height: 100vh;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }
                .container {
                    text-align: center;
                    padding: 3rem;
                    background: #1a1a2e;
                    border-radius: 16px;
                    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
                    max-width: 440px;
                    width: 90%;
                }
                .logo {
                    width: 48px;
                    height: 48px;
                    margin: 0 auto 1.5rem;
                    background: linear-gradient(135deg, #635bff, #00d4aa);
                    border-radius: 12px;
                }
                h1 {
                    font-size: 2rem;
                    font-weight: 700;
                    margin-bottom: 0.5rem;
                    color: #f8fafc;
                }
                p {
                    color: #94a3b8;
                    font-size: 1.05rem;
                    margin-bottom: 2rem;
                    line-height: 1.6;
                }
                .btn {
                    display: inline-block;
                    padding: 0.85rem 2.5rem;
                    background: linear-gradient(135deg, #635bff, #4f46e5);
                    color: #fff;
                    text-decoration: none;
                    border-radius: 8px;
                    font-size: 1rem;
                    font-weight: 600;
                    transition: transform 0.2s, box-shadow 0.2s;
                    box-shadow: 0 4px 14px rgba(99, 91, 255, 0.4);
                }
                .btn:hover {
                    transform: translateY(-2px);
                    box-shadow: 0 6px 20px rgba(99, 91, 255, 0.6);
                }
                .footer {
                    margin-top: 2rem;
                    font-size: 0.85rem;
                    color: #475569;
                }
                .footer a { color: #635bff; text-decoration: none; }
            </style>
        </head>
        <body>
            <div class="container">
                <div class="logo"></div>
                <h1>Go + Auth0</h1>
                <p>Secure authentication for your Go web application, powered by Auth0.</p>
                <a href="/login" class="btn">Sign In</a>
                <div class="footer">
                    Protected by <a href="https://auth0.com">Auth0</a>
                </div>
            </div>
        </body>
        </html>
        ```
      </Tab>

      <Tab title="user.html">
        ```html templates/user.html expandable lines theme={null}
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Profile</title>
            <style>
                * { margin: 0; padding: 0; box-sizing: border-box; }
                body {
                    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                    background: #0a0a0a;
                    color: #e2e8f0;
                    min-height: 100vh;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }
                .container {
                    text-align: center;
                    padding: 3rem;
                    background: #1a1a2e;
                    border-radius: 16px;
                    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
                    max-width: 440px;
                    width: 90%;
                }
                .avatar {
                    display: block;
                    width: 96px;
                    height: 96px;
                    border-radius: 50%;
                    border: 3px solid #635bff;
                    margin: 0 auto 1.5rem;
                    object-fit: cover;
                    background: #2d2d5e;
                }
                .avatar[src=""], .avatar:not([src]) {
                    display: none;
                }
                .avatar-fallback {
                    width: 96px;
                    height: 96px;
                    border-radius: 50%;
                    border: 3px solid #635bff;
                    margin: 0 auto 1.5rem;
                    background: linear-gradient(135deg, #635bff, #4f46e5);
                    display: none;
                    align-items: center;
                    justify-content: center;
                    font-size: 2rem;
                    font-weight: 700;
                    color: #fff;
                }
                .badge {
                    display: inline-block;
                    padding: 0.3rem 0.75rem;
                    background: rgba(0, 212, 170, 0.15);
                    color: #00d4aa;
                    border-radius: 20px;
                    font-size: 0.8rem;
                    font-weight: 600;
                    margin-bottom: 1rem;
                }
                h2 {
                    font-size: 1.75rem;
                    font-weight: 700;
                    color: #f8fafc;
                    margin-bottom: 0.25rem;
                }
                .email {
                    color: #94a3b8;
                    font-size: 1rem;
                    margin-bottom: 2rem;
                }
                .info-card {
                    background: #0f0f23;
                    border-radius: 10px;
                    padding: 1.25rem;
                    margin-bottom: 1.5rem;
                    text-align: left;
                }
                .info-row {
                    display: flex;
                    justify-content: space-between;
                    padding: 0.5rem 0;
                    border-bottom: 1px solid #1e293b;
                }
                .info-row:last-child { border-bottom: none; }
                .info-label { color: #64748b; font-size: 0.875rem; }
                .info-value { color: #e2e8f0; font-size: 0.875rem; font-weight: 500; }
                .btn-logout {
                    display: inline-block;
                    padding: 0.75rem 2rem;
                    background: transparent;
                    color: #f87171;
                    text-decoration: none;
                    border-radius: 8px;
                    font-size: 0.95rem;
                    font-weight: 600;
                    border: 1px solid #f87171;
                    transition: all 0.2s;
                }
                .btn-logout:hover {
                    background: #f87171;
                    color: #0a0a0a;
                }
            </style>
        </head>
        <body>
            <div class="container">
                <img class="avatar" src="{{ .picture }}" alt="{{ .name }}" onerror="this.style.display='none';document.getElementById('avatar-fallback').style.display='flex';" />
                <div id="avatar-fallback" class="avatar-fallback">{{ if .nickname }}{{ slice .nickname 0 1 }}{{ else }}?{{ end }}</div>
                <span class="badge">Authentifié</span>
                <h2>{{ .nickname }}</h2>
                <p class="email">{{ .email }}</p>
                <div class="info-card">
                    <div class="info-row">
                        <span class="info-label">Nom complet</span>
                        <span class="info-value">{{ .name }}</span>
                    </div>
                    <div class="info-row">
                        <span class="info-label">Surnom</span>
                        <span class="info-value">{{ .nickname }}</span>
                    </div>
                    <div class="info-row">
                        <span class="info-label">Courriel</span>
                        <span class="info-value">{{ .email }}</span>
                    </div>
                </div>
                <a href="/logout" class="btn-logout">Se déconnecter</a>
            </div>
        </body>
        </html>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Créez le serveur principal" stepNumber={6}>
    Assemblez le tout dans `main.go` :

    ```go main.go lines theme={null}
    package main

    import (
        "html/template"
        "log"
        "net/http"

        "github.com/joho/godotenv"
    )

    var templates *template.Template

    func main() {
        // Le fichier .env est facultatif ; dans Docker, les variables d'environnement proviennent de l'indicateur --env-file.
        godotenv.Load()

        initSessionStore()

        auth, err := NewAuthenticator()
        if err != nil {
            log.Fatalf("Failed to initialize the authenticator: %v", err)
        }

        templates = template.Must(template.ParseGlob("templates/*.html"))

        mux := http.NewServeMux()
        mux.HandleFunc("/", HomeHandler)
        mux.HandleFunc("/login", LoginHandler(auth))
        mux.HandleFunc("/callback", CallbackHandler(auth))
        mux.HandleFunc("/user", UserHandler)
        mux.HandleFunc("/logout", LogoutHandler(auth))

        log.Print("Server listening on http://localhost:3000/")
        if err := http.ListenAndServe("0.0.0.0:3000", mux); err != nil {
            log.Fatalf("There was an error with the http server: %v", err)
        }
    }
    ```

    <Accordion title="Structure du projet">
      ```
      myapp/
      ├── main.go          # Point d’entrée de l’application et routes
      ├── auth.go          # Configuration de l’application Auth0 et URL d’autorisation
      ├── handlers.go      # Gestionnaires HTTP (connexion, callback, déconnexion, profil)
      ├── templates/
      │   ├── home.html    # Page d’accueil avec lien de connexion
      │   └── user.html    # Page de profil de l’utilisateur
      ├── .env             # Variables d’environnement (non incluses dans le dépôt)
      ├── go.mod
      └── go.sum
      ```
    </Accordion>
  </Step>

  <Step title="Exécutez votre application et testez-la" stepNumber={7}>
    Démarrez le serveur de développement :

    ```shellscript theme={null}
    go run .
    ```

    Vous devriez voir : `Server listening on http://localhost:3000/`

    Ouvrez [http://localhost:3000](http://localhost:3000) dans votre navigateur. Cliquez sur **Sign In** pour être redirigé vers la page Universal Login d’Auth0. Une fois authentifié, vous serez redirigé vers votre application, où les renseignements de votre profil s’afficheront.

    <Info>
      Si le port 3000 est déjà utilisé, mettez à jour `AUTH0_CALLBACK_URL` dans votre fichier `.env`, ainsi que **Allowed Callback URLs** et **Allowed Logout URLs** dans les paramètres de votre application Auth0, pour utiliser le nouveau port.
    </Info>
  </Step>
</Steps>

<Check>
  **Point de contrôle**

  Vous devriez maintenant avoir une application Web Go entièrement fonctionnelle avec l’authentification Auth0, en cours d’exécution sur votre [localhost](http://localhost:3000/). Votre application :

  1. Redirige les utilisateurs vers Universal Login d’Auth0 pour s’authentifier
  2. Échange le code d’autorisation contre des jetons à l’aide du SDK `go-auth0`
  3. Récupère et affiche les renseignements du profil de l’utilisateur
  4. Prend en charge la déconnexion et le nettoyage de la session
</Check>

***

<div id="advanced-usage">
  ## Utilisation avancée
</div>

<Accordion title="Protéger les routes avec un middleware">
  Créez un middleware `IsAuthenticated` pour protéger les routes qui nécessitent une authentification. Ajoutez ceci à votre fichier `handlers.go` :

  ```go handlers.go theme={null}
  // IsAuthenticated est un middleware qui vérifie si
  // l'utilisateur a été authentifié.
  func IsAuthenticated(next http.Handler) http.Handler {
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          session, _ := store.Get(r, "auth-session")
          if session.Values["profile"] == nil {
              http.Redirect(w, r, "/", http.StatusSeeOther)
              return
          }
          next.ServeHTTP(w, r)
      })
  }
  ```

  Appliquez le middleware aux routes protégées dans `main.go` :

  ```go main.go theme={null}
  mux.Handle("/user", IsAuthenticated(http.HandlerFunc(UserHandler)))
  ```
</Accordion>

<Accordion title="Appeler une API protégée">
  Après l’authentification, le jeton d’accès stocké dans la session peut être utilisé pour appeler une API protégée :

  ```go theme={null}
  func ApiHandler(w http.ResponseWriter, r *http.Request) {
      session, _ := store.Get(r, "auth-session")
      accessToken, ok := session.Values["access_token"].(string)
      if !ok {
          http.Error(w, "Unauthorized", http.StatusUnauthorized)
          return
      }

      req, _ := http.NewRequest("GET", "https://your-api.example.com/api/private", nil)
      req.Header.Add("Authorization", "Bearer "+accessToken)

      res, err := http.DefaultClient.Do(req)
      if err != nil {
          http.Error(w, "API request failed", http.StatusInternalServerError)
          return
      }
      defer res.Body.Close()

      w.Header().Set("Content-Type", "application/json")
      io.Copy(w, res.Body)
  }
  ```

  <Note>
    Pour demander un jeton d’accès destiné à votre API, ajoutez le paramètre `audience` à l’URL d’autorisation dans `auth.go` :

    ```go theme={null}
    params := url.Values{
        "response_type": {"code"},
        "client_id":     {a.ClientID},
        "redirect_uri":  {a.CallbackURL},
        "scope":         {"openid profile email"},
        "audience":      {"https://your-api.example.com"},
        "state":         {state},
    }
    ```
  </Note>
</Accordion>

<Accordion title="Actualisation des jetons">
  Si votre application utilise des jetons d’actualisation, vous pouvez échanger un jeton d’actualisation contre un nouvel ensemble de jetons à l’aide du SDK `go-auth0` :

  ```go theme={null}
  newTokenSet, err := auth.OAuth.RefreshToken(r.Context(), oauth.RefreshTokenRequest{
      RefreshToken: storedRefreshToken,
  })
  ```

  Pour recevoir un jeton d’actualisation, ajoutez `offline_access` aux scopes dans votre URL d’autorisation :

  ```go theme={null}
  "scope": {"openid profile email offline_access"},
  ```
</Accordion>

***

<div id="troubleshooting">
  ## Dépannage
</div>

<AccordionGroup>
  <Accordion title="Problèmes courants et solutions">
    ### "Échec de l’échange du code d’autorisation contre un jeton"

    **Problème :** Le gestionnaire de rappel ne parvient pas à échanger le code d’autorisation.

    **Solutions :**

    1. Vérifiez que `AUTH0_CLIENT_SECRET` est correct dans votre fichier `.env`
    2. Assurez-vous que `AUTH0_CALLBACK_URL` correspond exactement aux **Allowed Callback URLs** dans les paramètres de votre application Auth0
    3. Vérifiez que le code d’autorisation n’a pas expiré (les codes sont à usage unique et valides pendant peu de temps)

    ### "Impossible de récupérer les renseignements de l’utilisateur"

    **Problème :** Le point de terminaison `/userinfo` renvoie une erreur.

    **Solutions :**

    1. Assurez-vous que le scope `openid` est inclus dans l’URL d’autorisation
    2. Vérifiez que le jeton d’accès est valide et n’a pas expiré
    3. Vérifiez la connectivité réseau vers votre Domaine Auth0

    ### "Paramètre state non valide"

    **Problème :** Le paramètre `state` dans le rappel ne correspond pas à la session.

    **Solutions :**

    1. Assurez-vous que les cookies sont activés dans votre navigateur
    2. Vérifiez que le secret du magasin de sessions n’a pas changé entre les requêtes
    3. Vérifiez que vous n’utilisez pas plusieurs onglets de navigateur pendant le flux de connexion

    ### Les utilisateurs ne peuvent pas se déconnecter

    **Problème :** Après avoir cliqué sur Déconnexion, les utilisateurs voient une page d’erreur Auth0.

    **Solutions :**

    1. Vérifiez que `http://localhost:3000` figure dans les **Allowed Logout URLs** dans les paramètres de votre application Auth0
    2. Assurez-vous que le paramètre `client_id` correspond à l’ID client de votre application
    3. Vérifiez que l’URL `returnTo` correspond exactement à l’une des URL de déconnexion autorisées

    ### Les données de session ne persistent pas

    **Problème :** Les données de profil de l’utilisateur disparaissent entre les requêtes.

    **Solutions :**

    1. Assurez-vous que `gob.Register(map[string]interface{}{})` est appelé avant de stocker les données
    2. Vérifiez que `session.Save(r, w)` est appelé après avoir modifié les valeurs de session
    3. Vérifiez que les cookies ne sont pas bloqués par les paramètres du navigateur
  </Accordion>
</AccordionGroup>

***

<div id="next-steps">
  ## Prochaines étapes
</div>

Maintenant que l’authentification fonctionne, vous pouvez aussi consulter :

* **[Profils utilisateur](/fr-CA/docs/manage-users/user-accounts/user-profiles)** — Découvrez les informations sur l’utilisateur disponibles après l’authentification
* **[Configurer d’autres fournisseurs d’identité](/fr-CA/docs/authenticate/identity-providers)** — Ajoutez des options de connexion sociale ou d’entreprise
* **[Activer l’authentification multifacteur](/fr-CA/docs/secure/multi-factor-authentication)** — Ajoutez une couche de sécurité supplémentaire
* **[Bonnes pratiques relatives aux jetons d’accès](/fr-CA/docs/secure/tokens/access-tokens)** — Découvrez les bonnes pratiques de sécurité des jetons
* **[Liste de contrôle pour la production](/fr-CA/docs/deploy-monitor/pre-deployment-checks/how-to-run-production-checks)** — Révision de sécurité avant le lancement

***

<div id="resources">
  ## Ressources
</div>

* **[go-auth0 GitHub](https://github.com/auth0/go-auth0)** — Code source et documentation
* **[Go Web App Sample](https://github.com/auth0-samples/auth0-golang-web-app/tree/master/01-Login-Quickstart)** — Exemple complet prêt à l’emploi
* **[Auth0 Community](https://community.auth0.com/)** — Obtenez de l’aide auprès de la communauté
