From 04acb45c760db04cadf51ead7f9fa6b00d55a74f Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sat, 13 Apr 2024 11:51:00 -0700 Subject: [PATCH] the portal can now validate jwt tokens and return errors when needed --- go.mod | 1 + go.sum | 2 ++ handlers/handler.go | 44 +++++++++++++++++++++++++++++++++++++++++++- services/config.go | 10 ++++++---- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index b3614a9..529da3d 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( require ( github.com/a-h/templ v0.2.648 + github.com/golang-jwt/jwt/v5 v5.2.1 github.com/gorilla/sessions v1.2.2 github.com/labstack/echo-contrib v0.16.0 github.com/labstack/echo/v4 v4.11.4 diff --git a/go.sum b/go.sum index 0e993ac..1fb95c0 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= diff --git a/handlers/handler.go b/handlers/handler.go index 7e66d2c..4cbfa70 100644 --- a/handlers/handler.go +++ b/handlers/handler.go @@ -1,12 +1,15 @@ package handlers import ( + "errors" "templ-test/client" "templ-test/models" "templ-test/services" + "time" "github.com/a-h/templ" + "github.com/golang-jwt/jwt/v5" "github.com/labstack/echo/v4" ) @@ -32,7 +35,9 @@ func NewHandlerClient(api client.ApiClient, cfg services.EnvConfig) *Handlers { func (h *Handlers) Register(group echo.Group) { group.GET("/", h.HomeHandler) - group.GET("/list", h.ListHandler) + group.GET("/settings", h.Settings) + group.POST("/settings", h.SettingsPost) + //group.GET("/list", h.ListHandler) auth := group.Group("/auth") auth.GET("/login", h.AuthLogin) @@ -46,6 +51,43 @@ func Render(ctx echo.Context, statusCode int, t templ.Component) error { return t.Render(ctx.Request().Context(), ctx.Response().Writer) } +type jwtToken struct { + Exp time.Time `json:"exp"` + Iss string `json:"iss"` + Authorized bool `json:"authorized"` + UserName string `json:"username"` + Scopes []string `json:"scopes"` + jwt.RegisteredClaims +} + +func ValidateJwt(ctx echo.Context, sharedSecret, issuer string) (jwtToken, error) { + cookies := GetCookieValues(ctx) + if cookies.Token == "" { + return jwtToken{}, errors.New("JWT Bearer Token is missing") + } + + token, err := jwt.ParseWithClaims(cookies.Token, &jwtToken{}, func(token *jwt.Token) (interface{}, error) { + return []byte(sharedSecret), nil + }) + if err != nil { + return jwtToken{}, err + } + + if !token.Valid { + return jwtToken{}, errors.New("invalid jwt token") + } + + claims := token.Claims.(*jwtToken) + if !claims.Exp.After(time.Now()) { + return jwtToken{}, errors.New("the jwt token has expired") + } + if claims.Iss != issuer { + return jwtToken{}, errors.New("the issuer was invalid") + } + + return *claims, nil +} + func GetCookieValues(ctx echo.Context) models.AllCookies { m := models.AllCookies{} diff --git a/services/config.go b/services/config.go index 94a0baf..84cc4cf 100644 --- a/services/config.go +++ b/services/config.go @@ -8,8 +8,9 @@ import ( ) type EnvConfig struct { - ApiServerUri string - CookieSecret string + ApiServerUri string + SharedApiSecret string + CookieSecret string } func NewEnvConfig() EnvConfig { @@ -22,7 +23,8 @@ func NewEnvConfig() EnvConfig { } return EnvConfig{ - ApiServerUri: os.Getenv("ApiServerUri"), - CookieSecret: os.Getenv("CookieSecret"), + ApiServerUri: os.Getenv("ApiServerUri"), + SharedApiSecret: os.Getenv("SharedApiSecret"), + CookieSecret: os.Getenv("CookieSecret"), } }