From 889f072390f5d053379c654b2eb429856aad5a5e Mon Sep 17 00:00:00 2001 From: Nik Afiq Date: Thu, 11 Dec 2025 23:16:30 +0900 Subject: [PATCH] feat(auth): add RequireAdmin middleware to enforce admin access control --- backend/internal/http/handlers.go | 2 +- backend/internal/http/middleware.go | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/backend/internal/http/handlers.go b/backend/internal/http/handlers.go index 44ba1fe..0be5f5b 100644 --- a/backend/internal/http/handlers.go +++ b/backend/internal/http/handlers.go @@ -34,7 +34,7 @@ func NewRouter(svc episode.UseCases, verifier auth.TokenVerifier, authEnabled bo if authEnabled && verifier != nil { protected := v1.Group("/") - protected.Use(AuthMiddleware(verifier)) + protected.Use(AuthMiddleware(verifier), RequireAdmin()) protected.DELETE("/shows", deleteShowsHandler(svc)) protected.POST("/archive", moveToArchiveHandler(svc)) } else { diff --git a/backend/internal/http/middleware.go b/backend/internal/http/middleware.go index 7084c25..4f01baf 100644 --- a/backend/internal/http/middleware.go +++ b/backend/internal/http/middleware.go @@ -4,6 +4,7 @@ import ( "net/http" "strings" + fbauth "firebase.google.com/go/v4/auth" "watch-party-backend/internal/auth" "github.com/gin-gonic/gin" @@ -31,3 +32,24 @@ func AuthMiddleware(verifier auth.TokenVerifier) gin.HandlerFunc { c.Next() } } + +// RequireAdmin enforces a custom claim "admin": true on the Firebase token. +func RequireAdmin() gin.HandlerFunc { + return func(c *gin.Context) { + val, ok := c.Get("firebaseToken") + if !ok { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + return + } + token, ok := val.(*fbauth.Token) + if !ok { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + return + } + if isAdmin, ok := token.Claims["admin"].(bool); !ok || !isAdmin { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "forbidden"}) + return + } + c.Next() + } +}