From 8f10fbfba1d49ab6c7d994becc83e842950daa30 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sun, 31 Mar 2024 17:49:09 -0700 Subject: [PATCH] mostly reworking how the JWT is processed --- api/handlers/v1/auth.go | 71 ++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/api/handlers/v1/auth.go b/api/handlers/v1/auth.go index 86a7828..93bcc98 100644 --- a/api/handlers/v1/auth.go +++ b/api/handlers/v1/auth.go @@ -2,9 +2,10 @@ package v1 import ( "errors" - "go-cook/api/models" + "go-cook/api/domain" "go-cook/api/repositories" "net/http" + "strings" "time" "github.com/golang-jwt/jwt/v5" @@ -15,19 +16,57 @@ const ( ErrJwtMissing = "auth token is missing" ErrJwtClaimsMissing = "claims missing on token" ErrJwtExpired = "auth token has expired" + ErrJwtScopeMissing = "required scope is missing" ) type JwtToken struct { Exp time.Time `json:"exp"` + Iss string `json:"iss"` Authorized bool `json:"authorized"` UserName string `json:"username"` - Token string `json:"token"` + Scopes []string `json:"scopes"` jwt.RegisteredClaims } -func generateJwt(username string) (string, error) { - //TODO use env here - secret := []byte("ThisIsABadSecretDontReallyUseThis") +func (j JwtToken) IsValid(scope string) error { + err := j.hasExpired() + if err != nil { + return err + } + + err = j.hasScope(scope) + if err != nil { + return err + } + + return nil +} + +func (j JwtToken) hasExpired() error { + // Check to see if the token has expired + hasExpired := j.Exp.Compare(time.Now()) + if hasExpired == -1 { + return errors.New(ErrJwtExpired) + } + return nil +} + +func (j JwtToken) hasScope(scope string) error { + // they have the scope to access everything, so let them pass. + if strings.Contains(domain.ScopeAll, scope) { + return nil + } + + for _, s := range j.Scopes { + if strings.Contains(s, scope) { + return nil + } + } + return errors.New(ErrJwtScopeMissing) +} + +func (h *Handler) generateJwt(username string) (string, error) { + secret := []byte(h.Config.JwtSecret) token := jwt.New(jwt.SigningMethodHS256) claims := token.Claims.(jwt.MapClaims) @@ -35,6 +74,10 @@ func generateJwt(username string) (string, error) { claims["authorized"] = true claims["username"] = username + var scopes []string + scopes = append(scopes, domain.ScopeRecipeRead) + claims["scopes"] = scopes + tokenString, err := token.SignedString(secret) if err != nil { return "", err @@ -50,7 +93,7 @@ func (h *Handler) AuthRegister(c echo.Context) error { // if we have an err, validate that if its not user not found. // if the user is not found, we can use that name if err.Error() != repositories.ErrUserNotFound { - return c.JSON(http.StatusInternalServerError, models.ErrorResponse{ + return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ HttpCode: http.StatusInternalServerError, Message: err.Error(), }) @@ -60,7 +103,7 @@ func (h *Handler) AuthRegister(c echo.Context) error { password := c.QueryParam("password") err = h.UserService.CheckPasswordForRequirements(password) if err != nil { - return c.JSON(http.StatusInternalServerError, models.ErrorResponse{ + return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ HttpCode: http.StatusInternalServerError, Message: err.Error(), }) @@ -68,7 +111,7 @@ func (h *Handler) AuthRegister(c echo.Context) error { _, err = h.userRepo.Create(username, password) if err != nil { - return c.JSON(http.StatusInternalServerError, models.ErrorResponse{ + return c.JSON(http.StatusInternalServerError, domain.ErrorResponse{ HttpCode: http.StatusInternalServerError, Message: err.Error(), }) @@ -93,7 +136,7 @@ func (h *Handler) AuthLogin(c echo.Context) error { return c.JSON(http.StatusInternalServerError, err) } - token, err := generateJwt(username) + token, err := h.generateJwt(username) if err != nil { return c.JSON(http.StatusInternalServerError, err) } @@ -101,6 +144,10 @@ func (h *Handler) AuthLogin(c echo.Context) error { return c.JSON(http.StatusOK, token) } +func (h *Handler) AddScope(c echo.Context) error { + +} + func (h *Handler) RefreshJwtToken(c echo.Context) error { return nil } @@ -118,11 +165,5 @@ func (h *Handler) getJwtToken(c echo.Context) (JwtToken, error) { return JwtToken{}, errors.New(ErrJwtClaimsMissing) } - // Check to see if the token has expired - hasExpired := claims.Exp.Compare(time.Now()) - if hasExpired == -1 { - return JwtToken{}, errors.New(ErrJwtExpired) - } - return *claims, nil }