> ## 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 en 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 obligatoire");
        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 du client :", 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 Auth0 App</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) + "*****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>;
};

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 le contrôle de version

  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 logout 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 tenant Auth0.
# Si vous utilisez un domaine personnalisé, utilisez plutôt cette valeur.
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

# Un long secret aléatoire utilisé pour chiffrer les cookies de session.
SESSION_SECRET=a-long-random-secret-key-for-cookie-encryption`;

<Steps>
  <Step title="Créer un nouveau 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 avoir une application configurée dans l’Auth0 Dashboard. L’application Auth0 est l’endroit où vous configurez l’authentification de votre projet.

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

    * **Domain**
    * **Client ID**
    * **Client Secret**

    <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 de configuration rapide (recommandé), exécuter une commande CLI ou faire la configuration manuellement dans le Dashboard :

    <Tabs>
      <Tab title="Configuration rapide (recommandée)">
        Créez une Auth0 App 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 dans le répertoire 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

          # Configurer l’application Auth0 et générer le fichier .env
          auth0 qs setup --app --type regular --framework vanilla-go --port 3000 --name "My Go App"
          ```

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

          # Configurer l’application Auth0 et générer le fichier .env
          auth0 qs setup --app --type regular --framework vanilla-go --port 3000 --name "My Go App"
          ```
        </CodeGroup>

        Après la création, copiez les valeurs **Domain**, **Client ID** et **Client Secret**, puis créez votre fichier `.env` :

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

        <Note>
          Cette commande va :

          1. Vérifier si vous êtes authentifié (et demander une connexion au besoin)
          2. Créer une Auth0 Regular Web Application configurée pour `http://localhost:3000`
          3. Générer un fichier `.env` avec votre domaine Auth0, votre ID client et votre secret client
        </Note>
      </Tab>

      <Tab title="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, entrez un nom pour votre application, sélectionnez `Regular Web Applications` comme type d’application, puis cliquez sur **Create**
        4. Passez à l’onglet **Settings** sur la page Application Details
        5. Prenez en note les valeurs **Domain**, **Client ID** et **Client Secret**

        ### Configurer les callback URLs

        Une callback URL 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** à :

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

        ### Configurer les Logout URLs

        Une logout URL est l’URL de votre application vers laquelle Auth0 peut rediriger l’utilisateur une fois sa session terminée. 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** à :

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

        ### Créez votre fichier d’environnement

        Créez un fichier `.env` dans le répertoire racine de votre projet avec les valeurs du 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 de 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 le client Auth0" stepNumber={3}>
    Créez le fichier `auth.go`. Ce fichier 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` à l’aide du domaine de votre tenant, de l’ID client et du secret client
    * Fournit l’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 handlers pour le login, le callback, le profil utilisateur et le logout.

    ```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, // Mettre à 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 callback 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 du 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 l'endpoint de logout 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 Universal Login d’Auth0
    * **CallbackHandler** échange le code d’autorisation contre des jetons à l’aide de `go-auth0`, puis appelle `UserInfo` pour obtenir le profil de l’utilisateur
    * **LogoutHandler** supprime la session et redirige vers l’endpoint `/v2/logout` d’Auth0
    * **UserHandler** récupère le profil à partir de la session et affiche le template
  </Step>

  <Step title="Créer des modèles 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">Authenticated</span>
                <h2>{{ .nickname }}</h2>
                <p class="email">{{ .email }}</p>
                <div class="info-card">
                    <div class="info-row">
                        <span class="info-label">Full Name</span>
                        <span class="info-value">{{ .name }}</span>
                    </div>
                    <div class="info-row">
                        <span class="info-label">Nickname</span>
                        <span class="info-value">{{ .nickname }}</span>
                    </div>
                    <div class="info-row">
                        <span class="info-label">Email</span>
                        <span class="info-value">{{ .email }}</span>
                    </div>
                </div>
                <a href="/logout" class="btn-logout">Sign Out</a>
            </div>
        </body>
        </html>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Créer le serveur principal" stepNumber={6}>
    Rassemblez 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’option --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 du client Auth0 et URL d’autorisation
      ├── handlers.go      # Gestionnaires HTTP (login, callback, logout, profil)
      ├── templates/
      │   ├── home.html    # Page d’accueil avec lien de connexion
      │   └── user.html    # Page de profil de l’utilisateur
      ├── .env             # Variables d’environnement (non versionnées)
      ├── go.mod
      └── go.sum
      ```
    </Accordion>
  </Step>

  <Step title="Exécutez et testez votre application" 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. Après vous être authentifié, vous serez redirigé vers votre application et verrez les informations de votre profil.

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

<Check>
  **Vérification**

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

  1. Redirige les utilisateurs vers le Universal Login d’Auth0 pour l’authentification
  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 utilisateur
  4. Prend en charge le logout et le nettoyage de la session
</Check>

***

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

<Accordion title="Protéger des routes à l’aide d’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="Actualiser les jetons">
  Si votre application utilise des refresh tokens, vous pouvez échanger un refresh token 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 refresh token, 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 handler de rappel ne peut 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 **URL de rappel autorisées** 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 de courte durée)

    ### "Échec de la récupération des informations utilisateur"

    **Problème :** Le endpoint `/userinfo` renvoie une erreur.

    **Solutions :**

    1. Assurez-vous que la portée `openid` est incluse 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 invalide"

    **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 logout, les utilisateurs voient une page d’erreur Auth0.

    **Solutions :**

    1. Vérifiez que `http://localhost:3000` figure dans les **URL de déconnexion autorisées** 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 sont pas enregistrées

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

    **Solutions :**

    1. Assurez-vous que `gob.Register(map[string]interface{}{})` est appelé avant d’enregistrer les données
    2. Vérifiez que `session.Save(r, w)` est appelé après la modification des 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, pensez aussi à explorer :

* **[Profils utilisateur](/docs/fr-ca/manage-users/user-accounts/user-profiles)** — Découvrez les renseignements sur l’utilisateur accessibles après l’authentification
* **[Configurer d’autres fournisseurs d’identité](/docs/fr-ca/authenticate/identity-providers)** — Ajoutez des options de connexion sociale ou d’entreprise
* **[Activer l’authentification multifactorielle](/docs/fr-ca/secure/multi-factor-authentication)** — Ajoutez un niveau de sécurité supplémentaire
* **[Bonnes pratiques pour les jetons d’accès](/docs/fr-ca/secure/tokens/access-tokens)** — Découvrez les bonnes pratiques de sécurité des jetons
* **[Liste de vérification pour la production](/docs/fr-ca/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
* **[Exemple d’application Web Go](https://github.com/auth0-samples/auth0-golang-web-app/tree/master/01-Login-Quickstart)** — Exemple complet et fonctionnel
* **[Auth0 Community](https://community.auth0.com/)** — Obtenez de l’aide auprès de la communauté
