64 lines
middleware/claims.go
JWT claim validation: parses and verifies the token's signature, audience, issuer, and expiry.
// Package middleware provides JWT-based request authentication for HTTP services.package middlewareimport ( "crypto/hmac" "crypto/sha256" "encoding/base64" "encoding/json" "errors" "strings")
// Claims holds the standard JWT payload fields validated by the middleware.type Claims struct { Sub string `json:"sub"` Iss string `json:"iss"` Aud string `json:"aud"` Exp int64 `json:"exp"` // Unix timestamp; the token is invalid after this time.}
var ( ErrMalformedToken = errors.New("jwt: malformed token") ErrInvalidSig = errors.New("jwt: signature verification failed") ErrWrongAudience = errors.New("jwt: audience mismatch") ErrWrongIssuer = errors.New("jwt: issuer mismatch") ErrExpiredToken = errors.New("jwt: token expired"))
// ValidateClaims parses a raw JWT string and returns the verified payload.// Returns an error if the token is malformed, the HMAC-SHA256 signature does not// match the provided secret, the audience or issuer claim is wrong, or the token is expired.// Parameters: token — the raw dot-separated JWT; secret — HMAC-SHA256 signing key;// wantAud — expected audience value; wantIss — expected issuer value.func ValidateClaims(token, secret, wantAud, wantIss string) (*Claims, error) { parts := strings.Split(token, ".") if len(parts) != 3 { return nil, ErrMalformedToken}
mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(parts[0] + "." + parts[1])) expectedSig := base64.RawURLEncoding.EncodeToString(mac.Sum(nil)) if !hmac.Equal([]byte(expectedSig), []byte(parts[2])) { return nil, ErrInvalidSig}
payload, err := base64.RawURLEncoding.DecodeString(parts[1]) if err != nil { return nil, ErrMalformedToken}
var c Claims if err := json.Unmarshal(payload, &c); err != nil { return nil, ErrMalformedToken}
if c.Aud != wantAud { return nil, ErrWrongAudience}
if c.Iss != wantIss { return nil, ErrWrongIssuer}
return &c, nil}