package auth import ( "errors" "time" "github.com/golang-jwt/jwt/v5" ) type Claims struct { Username string `json:"username"` Role string `json:"role"` jwt.RegisteredClaims } type JWTManager struct { secret []byte ttl time.Duration issuer string } func NewJWTManager(secret string, ttl time.Duration) *JWTManager { if secret == "" { secret = "insecure-jwt-secret-change-me" } if ttl == 0 { ttl = 2 * time.Hour } return &JWTManager{secret: []byte(secret), ttl: ttl, issuer: "live-sfu-demo"} } func (j *JWTManager) Sign(username, role string) (string, error) { now := time.Now() claims := Claims{ Username: username, Role: role, RegisteredClaims: jwt.RegisteredClaims{ Issuer: j.issuer, Subject: username, IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(j.ttl)), NotBefore: jwt.NewNumericDate(now), }, } tok := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return tok.SignedString(j.secret) } func (j *JWTManager) Verify(tokenStr string) (*Claims, error) { if tokenStr == "" { return nil, errors.New("empty token") } tok, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(t *jwt.Token) (interface{}, error) { if t.Method != jwt.SigningMethodHS256 { return nil, errors.New("unexpected signing method") } return j.secret, nil }) if err != nil { return nil, err } claims, ok := tok.Claims.(*Claims) if !ok || !tok.Valid { return nil, errors.New("invalid token") } return claims, nil } func (j *JWTManager) TTL() time.Duration { return j.ttl }