package token import ( "fmt" "github.com/golang-jwt/jwt/v5" log "github.com/sirupsen/logrus" "net/http" "strconv" "strings" "time" ) type JWT struct { SecretKey string Issuer string AccessExpire time.Duration RefreshExpire time.Duration } type Deps struct { SecretKey string Issuer string AccessExpire string RefreshExpire string } func NewJWT(deps Deps) *JWT { return &JWT{ SecretKey: deps.SecretKey, Issuer: deps.Issuer, AccessExpire: duration(deps.AccessExpire), RefreshExpire: duration(deps.RefreshExpire), } } func (j *JWT) CreateAccessToken(userUuid, sessionUuid string) (string, error) { now := time.Now() token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "exp": now.Add(j.AccessExpire).Unix(), "iat": now.Unix(), "iss": j.Issuer, "nbf": now.Unix(), "sub": userUuid, "sid": sessionUuid, }) signedToken, err := token.SignedString([]byte(j.SecretKey)) if err != nil { return "", err } return signedToken, nil } func (j *JWT) CreateRefreshToken(refreshUuid string, expires time.Time) *http.Cookie { return &http.Cookie{ Name: "refresh_uuid", Value: refreshUuid, Expires: expires, Secure: false, HttpOnly: true, SameSite: 3, Partitioned: false, } } func (j *JWT) Parse(token string) (string, error) { if strings.HasPrefix(token, "Bearer ") { token = strings.TrimPrefix(token, "Bearer ") } parse, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return []byte(j.SecretKey), nil }) if err != nil { log.Error(err) return "", err } if claims, ok := parse.Claims.(jwt.MapClaims); ok && parse.Valid { userUuid := claims["sub"].(string) return userUuid, nil } return "", fmt.Errorf("invalid token") } func (j *JWT) RefreshExpires() time.Duration { return j.RefreshExpire } func duration(minutes string) time.Duration { dur, err := strconv.Atoi(minutes) if err != nil { return time.Duration(10) * time.Minute } return time.Duration(dur) * time.Minute }