feat: migrate auth0mock from Node.js to Go

Refactor the application to a Go-based architecture for improved
performance and maintainability. Replace the Dockerfile to utilize a
multi-stage build process, enhancing image efficiency. Implement
comprehensive session store tests to ensure reliability and create
new OAuth handlers for managing authentication efficiently. Update 
documentation to reflect these structural changes.
This commit is contained in:
2025-12-29 16:30:37 +01:00
parent 96453e1d15
commit 9992fb4ef1
25 changed files with 1976 additions and 1991 deletions
+97
View File
@@ -0,0 +1,97 @@
package handlers
import (
"encoding/json"
"log/slog"
"net/http"
"gitlab.com/unboundsoftware/auth0mock/auth"
"gitlab.com/unboundsoftware/auth0mock/store"
)
// SessionHandler handles session-related endpoints
type SessionHandler struct {
jwtService *auth.JWTService
sessionStore *store.SessionStore
logger *slog.Logger
}
// NewSessionHandler creates a new session handler
func NewSessionHandler(jwtService *auth.JWTService, sessionStore *store.SessionStore, logger *slog.Logger) *SessionHandler {
return &SessionHandler{
jwtService: jwtService,
sessionStore: sessionStore,
logger: logger,
}
}
// UserInfo handles GET /userinfo
func (h *SessionHandler) UserInfo(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"picture": "https://cdn.playbuzz.com/cdn/5458360f-32ea-460e-a707-1a2d26760558/70bda687-cb84-4756-8a44-8cf735ed87b3.jpg",
})
}
// TokenInfo handles POST /tokeninfo
func (h *SessionHandler) TokenInfo(w http.ResponseWriter, r *http.Request) {
var req struct {
IDToken string `json:"id_token"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
if req.IDToken == "" {
h.logger.Debug("no token given in body")
http.Error(w, "missing id_token", http.StatusUnauthorized)
return
}
claims, err := h.jwtService.DecodeToken(req.IDToken)
if err != nil {
h.logger.Debug("failed to decode token", "error", err)
http.Error(w, "invalid id_token", http.StatusUnauthorized)
return
}
if userID, ok := claims["sub"].(string); ok {
h.logger.Debug("returning token data", "user_id", userID)
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(claims)
}
// Logout handles GET /v2/logout
func (h *SessionHandler) Logout(w http.ResponseWriter, r *http.Request) {
returnTo := r.URL.Query().Get("returnTo")
// Try to get session from cookie
cookie, err := r.Cookie("auth0")
if err == nil && cookie.Value != "" {
h.sessionStore.Delete(cookie.Value)
h.logger.Debug("deleted session", "code", cookie.Value)
}
// Clear the cookie
http.SetCookie(w, &http.Cookie{
Name: "auth0",
Value: "",
Path: "/",
MaxAge: -1,
SameSite: http.SameSiteNoneMode,
Secure: true,
HttpOnly: true,
})
if returnTo != "" {
http.Redirect(w, r, returnTo, http.StatusFound)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Logged out"))
}