Passer au contenu principal
Prérequis : Avant de commencer, assurez-vous d’avoir installé les éléments suivants :
  • Go 1.25 ou une version ultérieure
  • Git pour la gestion de versions
Vérifiez l’installation : go version

Pour commencer

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 et de la bibliothèque standard net/http de Go.
1

Créer un projet

Créez un nouveau répertoire pour votre application Go, puis initialisez un module.
mkdir myapp && cd myapp
go mod init myapp
Installez les dépendances requises :
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 :
mkdir templates
touch .env auth.go handlers.go main.go templates/home.html templates/user.html
go.mod
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
)
2

Configurez votre application Auth0

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
Tableau de bord de l’application
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 :
Créez une application Auth0 et copiez le fichier .env prérempli avec les bonnes valeurs de configuration.
Vérifiez que votre fichier .env existe : cat .env (Mac/Linux) ou type .env (Windows)
3

Créer l’application Auth0

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.
auth.go
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
4

Créer des gestionnaires de routes

Créez le fichier handlers.go avec des gestionnaires pour la connexion, le rappel, le profil utilisateur et la déconnexion.
handlers.go
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
5

Créer des gabarits HTML

templates/home.html
<!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>
6

Créez le serveur principal

Assemblez le tout dans main.go :
main.go
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)
    }
}
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
7

Exécutez votre application et testez-la

Démarrez le serveur de développement :
go run .
Vous devriez voir : Server listening on http://localhost:3000/Ouvrez 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.
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.
Point de contrôleVous devriez maintenant avoir une application Web Go entièrement fonctionnelle avec l’authentification Auth0, en cours d’exécution sur votre localhost. 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

Utilisation avancée

Créez un middleware IsAuthenticated pour protéger les routes qui nécessitent une authentification. Ajoutez ceci à votre fichier handlers.go :
handlers.go
// 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 :
main.go
mux.Handle("/user", IsAuthenticated(http.HandlerFunc(UserHandler)))
Après l’authentification, le jeton d’accès stocké dans la session peut être utilisé pour appeler une API protégée :
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)
}
Pour demander un jeton d’accès destiné à votre API, ajoutez le paramètre audience à l’URL d’autorisation dans auth.go :
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},
}
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 :
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 :
"scope": {"openid profile email offline_access"},

Dépannage

”É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

Prochaines étapes

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

Ressources