| name | mojoauth-oidc-hosted-page-go |
| description | Implement passwordless authentication in Go applications using MojoAuth OIDC Hosted Login Page. |
Implement MojoAuth OIDC (Go)
This expert AI assistant guide walks you through integrating passwordless authentication into a Go application using MojoAuth's Hosted Login Page as an OIDC identity provider. MojoAuth handles all authentication methods (Magic Links, Email OTP, SMS OTP, Social Login, Passkeys) through its hosted page.
1. Prerequisites
- An existing Go application (1.21+).
- Basic knowledge of Go's
net/http or a web framework like chi or gorilla/mux.
- An active MojoAuth account.
- MojoAuth OIDC Setup Guide
- Required packages:
github.com/coreos/go-oidc/v3/oidc, golang.org/x/oauth2.
2. Implementation Steps
Step 1: Configure Application in MojoAuth
- Log in to the MojoAuth Dashboard.
- Note your MojoAuth Domain (e.g.,
your-app.mojoauth.com).
- Configure the Redirect URI (e.g.,
http://localhost:8080/auth/callback).
- Retrieve Client ID and Client Secret.
- Enable your preferred authentication methods.
Step 2: Modify the Existing Go Project
Substep 2.1: Install Dependencies
go get github.com/coreos/go-oidc/v3/oidc
go get golang.org/x/oauth2
Substep 2.2: Configure Environment Variables
Set the following environment variables (or use a .env loader like godotenv):
MOJOAUTH_DOMAIN=your-app.mojoauth.com
MOJOAUTH_CLIENT_ID=your_client_id
MOJOAUTH_CLIENT_SECRET=your_client_secret
MOJOAUTH_REDIRECT_URI=http://localhost:8080/auth/callback
Substep 2.3: Configure OIDC Provider
Create a dedicated file for OIDC configuration (e.g., internal/auth/oidc.go):
package auth
import (
"context"
"fmt"
"os"
"github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2"
)
var (
OIDCProvider *oidc.Provider
OAuth2Config oauth2.Config
)
func InitOIDC() error {
ctx := context.Background()
issuerURL := fmt.Sprintf("https://%s", os.Getenv("MOJOAUTH_DOMAIN"))
provider, err := oidc.NewProvider(ctx, issuerURL)
if err != nil {
return err
}
OIDCProvider = provider
OAuth2Config = oauth2.Config{
ClientID: os.Getenv("MOJOAUTH_CLIENT_ID"),
ClientSecret: os.Getenv("MOJOAUTH_CLIENT_SECRET"),
RedirectURL: os.Getenv("MOJOAUTH_REDIRECT_URI"),
Endpoint: provider.Endpoint(),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}
return nil
}
Substep 2.4: Update Login Page/UI
Since MojoAuth handles all authentication on its Hosted Login Page, your login page only needs a "Sign In" link:
<!DOCTYPE html>
<html>
<head><title>Sign In</title></head>
<body>
<div class="login-container">
<h1>Welcome</h1>
<p>Sign in with your preferred method — passwordless, social login, or passkeys.</p>
{{if .Error}}
<p style="color: red;">{{.Error}}</p>
{{end}}
<a href="/auth/login" class="sign-in-button">Sign In with MojoAuth</a>
<p class="powered-by">Powered by MojoAuth — Passwordless Authentication</p>
</div>
</body>
</html>
Substep 2.5: Update Backend Logic
Create the necessary handlers to process the OIDC flow.
1. Login Handler (internal/auth/handlers.go):
package auth
import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"log"
"net/http"
"github.com/coreos/go-oidc/v3/oidc"
)
func generateState() string {
b := make([]byte, 16)
rand.Read(b)
return base64.URLEncoding.EncodeToString(b)
}
func LoginHandler(w http.ResponseWriter, r *http.Request) {
state := generateState()
http.SetCookie(w, &http.Cookie{
Name: "oidc_state",
Value: state,
Path: "/",
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteLaxMode,
MaxAge: 3600,
})
authURL := OAuth2Config.AuthCodeURL(state)
http.Redirect(w, r, authURL, http.StatusFound)
}
2. Callback Handler (add to internal/auth/handlers.go):
func CallbackHandler(w http.ResponseWriter, r *http.Request) {
stateCookie, err := r.Cookie("oidc_state")
if err != nil {
log.Println("State cookie not found:", err)
http.Redirect(w, r, "/login?error=state_missing", http.StatusFound)
return
}
if r.URL.Query().Get("state") != stateCookie.Value {
log.Println("State mismatch")
http.Redirect(w, r, "/login?error=state_mismatch", http.StatusFound)
return
}
code := r.URL.Query().Get("code")
token, err := OAuth2Config.Exchange(r.Context(), code)
if err != nil {
log.Println("Token exchange failed:", err)
http.Redirect(w, r, "/login?error=token_exchange_failed", http.StatusFound)
return
}
rawIDToken, ok := token.Extra("id_token").(string)
if !ok {
log.Println("No id_token in response")
http.Redirect(w, r, "/login?error=no_id_token", http.StatusFound)
return
}
verifier := OIDCProvider.Verifier(&oidc.Config{ClientID: OAuth2Config.ClientID})
idToken, err := verifier.Verify(r.Context(), rawIDToken)
if err != nil {
log.Println("ID token verification failed:", err)
http.Redirect(w, r, "/login?error=token_verification_failed", http.StatusFound)
return
}
var claims []{}
err := idToken.Claims(&claims); err != {
log.Println(, err)
http.Redirect(w, r, , http.StatusFound)
}
http.SetCookie(w, &http.Cookie{
Name: ,
Value: ,
Path: ,
MaxAge: ,
})
claimsJSON, _ := json.Marshal(claims)
http.SetCookie(w, &http.Cookie{
Name: ,
Value: base64.URLEncoding.EncodeToString(claimsJSON),
Path: ,
HttpOnly: ,
MaxAge: ,
})
log.Println(, claims)
http.Redirect(w, r, , http.StatusFound)
}
3. Main Application Setup (main.go):
package main
import (
"log"
"net/http"
"html/template"
"yourmodule/internal/auth"
)
func main() {
if err := auth.InitOIDC(); err != nil {
log.Fatal("Failed to initialize OIDC:", err)
}
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("templates/login.html"))
data := map[string]string{"Error": r.URL.Query().Get("error")}
tmpl.Execute(w, data)
})
http.HandleFunc("/auth/login", auth.LoginHandler)
http.HandleFunc("/auth/callback", auth.CallbackHandler)
http.HandleFunc("/dashboard", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("<h1>Dashboard</h1><p>Welcome!</p>"))
})
log.Println("Server running on http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Step 3: Test the Implementation
- Start your application:
go run main.go.
- Navigate to
http://localhost:8080/login.
- Click "Sign In with MojoAuth".
- You should be redirected to the MojoAuth Hosted Login Page.
- Authenticate using any available method.
- After successful authentication, you should be redirected back to
/auth/callback and then to /dashboard.
3. Additional Considerations
- Error Handling: Enhance the callback handler with granular OIDC error parsing.
- Styling: Adapt the example HTML/CSS to match your application's design system.
- Security: Use a proper session library (e.g.,
gorilla/sessions) instead of raw cookies in production.
- Environment Variables: Use a library like
godotenv for local development and proper secrets management in production.
4. Support