On the Echo framework website I followed their guide to creating a jwt and created a custom claims type to store and pass the user’s email to other requests. However, after following their guide I created a function to store the token to the database and it returns an error stating that it couldn’t convert the claim to a jwt when trying to retrieve the value from the “email” key. I tested to see if the funct that creates the jwt was the issue and it returned the encoded token just fine. So how am I supposed to pass the jwt to my email funct to get the value out of it?
sessionmanager
type Session struct {
Token string
Data string
Expiry time.Time
}
type UserCustomClaims struct {
Email string `json:"email"`
jwt.RegisteredClaims
}
func Email(c echo.Context) (string, error) {
user, ok := c.Get("user").(*jwt.Token)
if !ok {
return "", echo.NewHTTPError(http.StatusBadRequest, "error:sessionamanager: failed to convert to jwt token")
}
claims, ok := user.Claims.(*UserCustomClaims)
if !ok {
return "", echo.NewHTTPError(http.StatusBadRequest, "error:sessionamanager: failed to convert to customs claims type")
}
email := claims.Email
if email == "" {
return "", echo.NewHTTPError(http.StatusBadRequest, "failed to convert email")
}
return email, nil
}
// adds user token to sessions table in database
func CreateToken(usr string, c echo.Context) (*jwt.Token, error) {
expirDate := time.Now().Add(time.Hour * 72).Unix()
claims := &UserCustomClaims{
Email: usr,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Unix(expirDate, 0)),
},
}
fmt.Printf("foo: %v\n", claims.Email)
// Create token with claims
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token, nil
}
// adds user token to sessions table in database
func AddToken(tk *jwt.Token, c echo.Context) error {
ctx, db := backend.Connect()
defer db.Close()
// Generate encoded token and send it as response.
t, err := tk.SignedString([]byte("secret"))
if err != nil {
return err
}
email, emailErr := Email(c)
if emailErr != nil {
return fmt.Errorf("error: failed to retreive to email from claim: %w", emailErr)
}
expTime, err := tk.Claims.GetExpirationTime()
// err retrieving expiration time
if err != nil {
return errors.New("error: failed to get expiration time")
}
// insert token
_, err = db.Exec(
ctx,
`INSERT INTO sessions (token, data, expiry) VALUES($1, $2, $3)`,
t, email, expTime.Time,
)
// handle multiple errs when insertion goes wrong
if err != nil {
return fmt.Errorf("error: failed to add usersession: %w", err)
}
return nil
}
Main File
import (
"errors"
"fmt"
"html/template"
"io"
"log"
"net/http"
"scriptmang/drumstick/internal/sessionmanager"
"github.com/golang-jwt/jwt/v5"
echojwt "github.com/labstack/echo-jwt/v4"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
type TemplateManager struct {
templates *template.Template
}
func (tm *TemplateManager) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
if viewContext, isMap := data.(map[string]interface{}); isMap {
viewContext["reverse"] = c.Echo().Reverse
}
err := tm.templates.ExecuteTemplate(w, name, data)
if err != nil {
log.Println("template not found")
}
return err
}
func loginForm(c echo.Context) error {
str := "Login to Drumstick"
return c.Render(http.StatusOK, "loginForm", str)
}
func vetLogin(c echo.Context) error {
usr := c.FormValue("email")
pswd := c.FormValue("password")
rsltErr := accts.CompareUserCreds(usr, pswd)
if rsltErr != nil {
return echo.NewHTTPError(http.StatusUnauthorized, rsltErr)
}
tk, err := sessionmanager.CreateToken(usr, c)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err)
}
// store the token to the database
err = sessionmanager.AddToken(tk, c)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err)
}
return c.Render(http.StatusOK, "posts", "Add Posts to Your Feed")
}
func main() {
tm := &TemplateManager{
templates: template.Must(template.ParseGlob("ui/html/pages/*[^#?!|].tmpl")),
}
router.Renderer = tm
router := echo.New()
router.Use(middleware.SecureWithConfig(middleware.DefaultSecureConfig))
router.Use(middleware.Logger())
router.Use(middleware.Recover())
router.GET("/loginForm", loginForm)
router.POST("/posts", vetLogin)
// Configure middleware with the custom claims type
config := echojwt.Config{
NewClaimsFunc: func(c echo.Context) jwt.Claims {
return new(sessionmanager.UserCustomClaims)
},
SigningKey: []byte("secret"),
}
router.Use(echojwt.WithConfig(config))
router.Logger.Fatal(router.Start(":8080"))
}