diff --git a/backend/handlers/handle_auth.go b/backend/handlers/handle_auth.go new file mode 100644 index 0000000..ef42ace --- /dev/null +++ b/backend/handlers/handle_auth.go @@ -0,0 +1,125 @@ +package handlers + +import ( + "net/http" + + "adam-french.co.uk/backend/models" + "github.com/gin-gonic/gin" + "golang.org/x/crypto/bcrypt" +) + +func (store *Store) AuthMiddlewear(ctx *gin.Context) { + + access_token, err := ctx.Cookie("access_token") + if err != nil { + ctx.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"}) + return + } + + claims, err := store.Auth.VerifyJWT(access_token) + if err != nil { + ctx.AbortWithStatusJSON(401, gin.H{"error": err.Error()}) + return + } + + // store claims in Gin context + ctx.Set("userClaims", claims) + ctx.Next() +} + +func (store *Store) RefreshToken(ctx *gin.Context) { + refreshToken, err := ctx.Cookie("refresh_token") + if err != nil { + ctx.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()}) + return + } + + claims, err := store.Auth.VerifyJWT(refreshToken) + if err != nil { + ctx.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()}) + } + + userId, ok := (*claims)["id"].(uint) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid token claims"}) + return + } + + user := models.User{} + tx := store.DB.First(&user, userId) + if tx.Error != nil { + ctx.JSON(http.StatusNotFound, gin.H{"error": tx.Error.Error()}) + return + } + + tokens, err := store.Auth.GenerateJWT(&user) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.SetCookie( + "access_token", + tokens.AccessToken, + int(store.Auth.Config.AccessTokenLifetime.Seconds()), + store.Auth.Config.Endpoint, + store.Auth.Config.Domain, + true, true, + ) + ctx.SetCookie( + "refresh_token", + tokens.RefreshToken, + int(store.Auth.Config.RefreshTokenLifetime.Seconds()), + store.Auth.Config.Endpoint, + store.Auth.Config.Domain, + true, true, + ) + + ctx.JSON(http.StatusAccepted, gin.H{"data": user}) + +} + +func (store *Store) Login(ctx *gin.Context) { + var input UserCredentials + if err := ctx.ShouldBindBodyWithJSON(&input); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + user := models.User{Username: input.Username} + if err := store.DB.Where("username = ?", input.Username).First(&user).Error; err != nil { + ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()}) + return + } + + if err := bcrypt.CompareHashAndPassword(user.Password, []byte(input.Password)); err != nil { + ctx.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()}) + return + } + + // Generate JWT token + tokens, err := store.Auth.GenerateJWT(&user) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.SetCookie( + "access_token", + tokens.AccessToken, + int(store.Auth.Config.AccessTokenLifetime.Seconds()), + store.Auth.Config.Endpoint, + store.Auth.Config.Domain, + true, true, + ) + ctx.SetCookie( + "refresh_token", + tokens.RefreshToken, + int(store.Auth.Config.RefreshTokenLifetime.Seconds()), + store.Auth.Config.Endpoint, + store.Auth.Config.Domain, + true, true, + ) + + ctx.JSON(http.StatusAccepted, gin.H{"data": user}) +}