package auth import ( "errors" "time" "github.com/golang-jwt/jwt/v5" ) var ErrInvalidToken = errors.New("token invalide") // Claims du token Omnex : porte le rôle et l'identifiant de session Redis (sid). // La signature (secret) authentifie le token ; le sid permet la révocation. type Claims struct { Role Role `json:"role"` Username string `json:"username"` SessionID string `json:"sid"` jwt.RegisteredClaims } // Issuer signe et vérifie des JWT HS256. type Issuer struct { secret []byte ttl time.Duration } func NewIssuer(secret []byte, ttl time.Duration) *Issuer { return &Issuer{secret: secret, ttl: ttl} } // Issue crée un token pour un utilisateur, lié à une session Redis (sid). func (i *Issuer) Issue(userID string, username string, role Role, sid string) (string, error) { now := time.Now() claims := Claims{ Role: role, SessionID: sid, Username: username, RegisteredClaims: jwt.RegisteredClaims{ Subject: userID, IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(i.ttl)), NotBefore: jwt.NewNumericDate(now), Issuer: "omnex", }, } return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(i.secret) } // Verify valide la signature + l'expiration et renvoie les claims. func (i *Issuer) Verify(tokenStr string) (*Claims, error) { claims := &Claims{} _, err := jwt.ParseWithClaims(tokenStr, claims, func(t *jwt.Token) (any, error) { // Refuse tout algo autre que HS256 (protection alg-confusion). if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { return nil, ErrInvalidToken } return i.secret, nil }) if err != nil { return nil, ErrInvalidToken } return claims, nil }