package jwtutil import ( "errors" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/golang-jwt/jwt/v5" ) var ( ErrExpiredToken = errors.New("token expired") ErrMalformedToken = errors.New("token malformed") ErrTokenNotExpired = errors.New("token not expired") ErrRefreshTokenNotFound = errors.New("refresh token not found") ) type UserClaim struct { jwt.RegisteredClaims UserId int64 Role domain.Role CompanyID domain.ValidInt64 } type PopOKClaim struct { jwt.RegisteredClaims UserID int64 `json:"user_id"` Username string `json:"username"` Currency string `json:"currency"` Lang string `json:"lang"` Mode string `json:"mode"` SessionID string `json:"session_id"` CompanyID domain.ValidInt64 `json:"company_id"` } type JwtConfig struct { JwtAccessKey string JwtAccessExpiry int } func CreateJwt(userId int64, Role domain.Role, CompanyID domain.ValidInt64, key string, expiry int) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaim{ RegisteredClaims: jwt.RegisteredClaims{ Issuer: "github.com/lafetz/snippitstash", IssuedAt: jwt.NewNumericDate(time.Now()), Audience: jwt.ClaimStrings{"fortune.com"}, NotBefore: jwt.NewNumericDate(time.Now()), ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(expiry) * time.Second)), }, UserId: userId, Role: Role, CompanyID: CompanyID, }) jwtToken, err := token.SignedString([]byte(key)) return jwtToken, err } func CreatePopOKJwt(userID int64, CompanyID domain.ValidInt64, username, currency, lang, mode, sessionID, key string, expiry time.Duration) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, PopOKClaim{ RegisteredClaims: jwt.RegisteredClaims{ Issuer: "fortune-bet", Audience: jwt.ClaimStrings{"popokgaming.com"}, IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), ExpiresAt: jwt.NewNumericDate(time.Now().Add(expiry)), }, UserID: userID, Username: username, // ✅ Must be a valid string Currency: currency, Lang: lang, Mode: mode, SessionID: sessionID, CompanyID: CompanyID, }) return token.SignedString([]byte(key)) } func ParseJwt(jwtToken string, key string) (*UserClaim, error) { token, err := jwt.ParseWithClaims(jwtToken, &UserClaim{}, func(token *jwt.Token) (interface{}, error) { return []byte(key), nil }) if err != nil { if errors.Is(err, jwt.ErrTokenExpired) { return nil, ErrExpiredToken } if errors.Is(err, jwt.ErrTokenMalformed) { return nil, ErrMalformedToken } return nil, err } if claims, ok := token.Claims.(*UserClaim); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token claims") } func ParsePopOKJwt(jwtToken string, key string) (*PopOKClaim, error) { token, err := jwt.ParseWithClaims(jwtToken, &PopOKClaim{}, func(token *jwt.Token) (interface{}, error) { return []byte(key), nil }) if err != nil { if errors.Is(err, jwt.ErrTokenExpired) { return nil, ErrExpiredToken } if errors.Is(err, jwt.ErrTokenMalformed) { return nil, ErrMalformedToken } return nil, err } if claims, ok := token.Claims.(*PopOKClaim); ok && token.Valid { return claims, nil } return nil, errors.New("invalid PopOK token claims") }