diff --git a/internal/app/server/middleware.go b/internal/app/server/middleware.go index 969f6ca..4eb7d6e 100644 --- a/internal/app/server/middleware.go +++ b/internal/app/server/middleware.go @@ -1,10 +1,7 @@ package server import ( - "errors" "fmt" - "log" - "net/http" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" @@ -20,38 +17,20 @@ func DepedencyInjectionMiddleware(deps *domain.InjectedDependencies) gin.Handler } } +// JwtAuthMiddleWare handles collection the JWT from the browser's cookies and setting the +// appropriate data. If the data is not found, this middleware will do effectively nothing, by not +// setting any values. Protected routes can use this lack of a value as a sign that the user is not +// logged in and direct the user to login. func JwtAuthMiddleWare(jwtSecretKey []byte) gin.HandlerFunc { return func(ctx *gin.Context) { - // NOTE: Option One: From auth header - // - // authHeader := ctx.GetHeader("Authorization") - // - // if authHeader == "" { - // ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization required."}) - // ctx.Abort() - // return - // } - // - // parts := strings.SplitN(authHeader, " ", 2) - // if !(len(parts) == 2 && parts[0] == "Bearer") { - // ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header must be Bearer token"}) - // ctx.Abort() - // return - // } - // - // tokenString := parts[1] - - // TODO: How are we handling faliure? - + // JWT cookie not found tokenString, err := ctx.Cookie("jwt_token") if err != nil { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "JWT token cookie not found"}) - ctx.Abort() + ctx.Next() return } claims := &domain.JwtClaims{} - // token, err := jwt.ParseWithClaims(tokenString, claims, ) token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { @@ -60,22 +39,29 @@ func JwtAuthMiddleWare(jwtSecretKey []byte) gin.HandlerFunc { return jwtSecretKey, nil }) + // Error occurred when parsing if err != nil { - if errors.Is(err, jwt.ErrSignatureInvalid) { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token signature"}) - } else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Token expired or not yet valid"}) - } else { - log.Printf("JWT parsing error: %v", err) - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) - } - ctx.Abort() + ctx.Next() return } + // NOTE: If we need deeper error handling + // if err != nil { + // if errors.Is(err, jwt.ErrSignatureInvalid) { + // ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token signature"}) + // } else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) { + // ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Token expired or not yet valid"}) + // } else { + // log.Printf("JWT parsing error: %v", err) + // ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) + // } + // ctx.Abort() + // return + // } + + // Token is invalid if !token.Valid { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) - ctx.Abort() + ctx.Next() return } diff --git a/internal/app/server/server.go b/internal/app/server/server.go index 99f2d9b..e41cfbd 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -135,6 +135,11 @@ func (s *Server) Setup() *Server { // API router endpoints router_api.GET("/", func(ctx *gin.Context) { ctx.JSON(200, gin.H{"message": "Server is active."}) }) router_api.GET("/tmp", func(ctx *gin.Context) { + if !domain.IsLoggedIn(ctx) { + ctx.JSON(200, gin.H{"error": "User is not logged in. Please login to continue"}) + return + } + userId := ctx.MustGet("userId").(int) userEmail := ctx.MustGet("userEmail").(string) diff --git a/internal/domain/server/server.go b/internal/domain/server/server.go index d8d8e3b..8fce0f5 100644 --- a/internal/domain/server/server.go +++ b/internal/domain/server/server.go @@ -1,6 +1,7 @@ package domain import ( + "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" domainAuth "github.com/haydenhargreaves/Potion/internal/domain/auth" domainUser "github.com/haydenhargreaves/Potion/internal/domain/user" @@ -16,3 +17,10 @@ type JwtClaims struct { Email string `json:"email"` jwt.RegisteredClaims } + +// IsLoggedIn checks the cookies in a request and returns whether the user is logged in. +func IsLoggedIn(ctx *gin.Context) bool { + _, id := ctx.Get("userId") + _, email := ctx.Get("userEmail") + return id && email +}