Skip to content

golang-jwt

SecuritySecurity/AuthenticationGo

What it is

golang-jwt is the maintained community fork of dgrijalva/jwt-go, providing JSON Web Token signing, parsing and validation.

Create tokens with registered and custom claims, sign them with HMAC or RSA, and parse incoming tokens with explicit algorithm and claim validation.

Installation

go get -u github.com/golang-jwt/jwt/v5

Getting started

The smallest useful thing you can do with it, and what each part means.

Issue and verify
type Claims struct {
    UserID string `json:"uid"`
    Role   string `json:"role"`
    jwt.RegisteredClaims
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, Claims{
    UserID: "42",
    Role:   "admin",
    RegisteredClaims: jwt.RegisteredClaims{
        ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)),
        IssuedAt:  jwt.NewNumericDate(time.Now()),
        Issuer:    "library-api",
    },
})
signed, err := token.SignedString(secret)
Short expiry is deliberate: a JWT cannot be revoked before it expires, so keep access tokens minutes long and use a refresh token for longer sessions.

Advanced usage

Where the library earns its place over a simpler alternative.

Parsing safely
parsed, err := jwt.ParseWithClaims(raw, &Claims{},
    func(t *jwt.Token) (any, error) {
        // Critical: pin the algorithm. Without this check an attacker can
        // present a token signed with "none" or a different scheme.
        if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("unexpected algorithm %v", t.Header["alg"])
        }
        return secret, nil
    },
    jwt.WithValidMethods([]string{"HS256"}),
    jwt.WithIssuer("library-api"),
    jwt.WithExpirationRequired(),
)

claims, ok := parsed.Claims.(*Claims)
if !ok || !parsed.Valid {
    return ErrUnauthorized
}
The algorithm check is the single most important line. The classic JWT vulnerability is a server that trusts the alg header from the token it is trying to verify.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

token signature is invalid
The signing key differs from the verification key, or the token was altered. Confirm both sides use the same secret.
token is expired
Check with errors.Is(err, jwt.ErrTokenExpired) and return 401 so the client refreshes rather than treating it as a server fault.

Best practices

  • Always pin accepted algorithms with WithValidMethods and verify the method in the keyfunc.
  • Keep access tokens short-lived; JWTs cannot be revoked once issued.
  • Never put secrets or personal data in claims — the payload is base64, not encrypted.
  • Migrate off github.com/dgrijalva/jwt-go, which is unmaintained and has a known CVE.

Background

Why it exists, and what it was reacting to.

The original jwt-go was abandoned with an open CVE around token validation. The community forked it as golang-jwt to ship the fix and take over maintenance — any project still importing the old path should migrate.