package accounts import ( "fmt" "os" "time" "github.com/golang-jwt/jwt/v5" ) type jwtClaims struct { UserID uint `json:"user_id"` Role string `json:"role"` jwt.RegisteredClaims } const ( RoleAdmin = "admin" RoleUser = "user" ) func GenerateTokens(userID uint, role string) (string, string, error) { accessSecret := os.Getenv("JWT_SECRET") refreshSecret := os.Getenv("JWT_REFRESH_SECRET") if accessSecret == "" || refreshSecret == "" { return "", "", fmt.Errorf("JWT secrets are not set") } normalizedRole := normalizeRole(role) // Access Token accessClaims := jwtClaims{ UserID: userID, Role: normalizedRole, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)), IssuedAt: jwt.NewNumericDate(time.Now()), }, } accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims) accessString, err := accessToken.SignedString([]byte(accessSecret)) if err != nil { return "", "", err } // Refresh Token refreshClaims := jwtClaims{ UserID: userID, Role: normalizedRole, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)), IssuedAt: jwt.NewNumericDate(time.Now()), }, } refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims) refreshString, err := refreshToken.SignedString([]byte(refreshSecret)) if err != nil { return "", "", err } return accessString, refreshString, nil } func ParseAccessToken(tokenString string) (uint, error) { secret := os.Getenv("JWT_SECRET") claims, err := parseTokenClaims(tokenString, secret) if err != nil { return 0, err } return claims.UserID, nil } func ParseRefreshToken(tokenString string) (uint, error) { secret := os.Getenv("JWT_REFRESH_SECRET") claims, err := parseTokenClaims(tokenString, secret) if err != nil { return 0, err } return claims.UserID, nil } func parseAccessClaims(tokenString string) (*jwtClaims, error) { secret := os.Getenv("JWT_SECRET") return parseTokenClaims(tokenString, secret) } func parseTokenClaims(tokenString, secret string) (*jwtClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &jwtClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte(secret), nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*jwtClaims); ok && token.Valid { claims.Role = normalizeRole(claims.Role) return claims, nil } return nil, fmt.Errorf("invalid token") } func normalizeRole(role string) string { switch role { case RoleAdmin: return RoleAdmin default: return RoleUser } }