package jwt import ( "errors" "time" "github.com/aykhans/oh-my-chat/internal/core/domain" "github.com/golang-jwt/jwt/v5" "github.com/google/uuid" ) type JWTService struct { key string duration time.Duration } type tokenPayload struct { UserID uuid.UUID `json:"user_id,omitempty"` jwt.RegisteredClaims } func NewJWTService(duration time.Duration, key string) *JWTService { return &JWTService{ key: key, duration: duration, } } func (jwtService *JWTService) CreateToken( user *domain.User, ) (string, error) { token := jwt.NewWithClaims( jwt.SigningMethodHS256, &tokenPayload{ UserID: user.ID, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate( time.Now().Add(jwtService.duration), ), Audience: jwt.ClaimStrings{"user"}, IssuedAt: jwt.NewNumericDate(time.Now()), }, }, ) tokenStr, err := token.SignedString([]byte(jwtService.key)) if err != nil { return "", domain.ErrTokenCreation } return tokenStr, nil } func (jwtService *JWTService) VerifyToken( token string, ) (*domain.AuthPayload, error) { keyFunc := func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, domain.ErrInvalidToken } return []byte(jwtService.key), nil } parsedToken, err := jwt.ParseWithClaims(token, &tokenPayload{}, keyFunc) if err != nil { if errors.Is(err, jwt.ErrTokenExpired) { return nil, domain.ErrExpiredToken } if errors.Is(err, jwt.ErrSignatureInvalid) { return nil, domain.ErrInvalidToken } return nil, domain.ErrInternal } payload := parsedToken.Claims.(*tokenPayload) return &domain.AuthPayload{UserID: payload.UserID}, nil }