v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
HIGH AI PREVALENCE: HIGH auth.go.jwt.hardcoded-secret

A JWT HMAC signing/verification key is hardcoded as a string literal in a call to golang-jwt.

Why AI tools produce this: AI coding tools generate this anti-pattern by default, it appears in a large share of AI-written auth code.

Why this matters

Anyone who can read the source or git history can forge or tamper with tokens, which is a complete authentication bypass.

Load the secret from the environment or a secret manager instead, e.g. key := []byte(os.Getenv("JWT_SECRET")) and token.SignedString(key). Never commit signing keys to source control.

VULNERABLE
vulnerable.go
package main

import (
	"github.com/golang-jwt/jwt/v5"
)

func signWithLiteral() (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"sub": "1234567890",
	})
	// ruleid: auth.go.jwt.hardcoded-secret
	return token.SignedString([]byte("super-secret-signing-key"))
}

func parseWithLiteralKeyfunc(tokenString string) (*jwt.Token, error) {
	return jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
		// ruleid: auth.go.jwt.hardcoded-secret
		return []byte("super-secret-signing-key"), nil
	})
}
SAFE
safe.go
package main

import (
	"os"

	"github.com/golang-jwt/jwt/v5"
)

func signFromEnv() (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"sub": "1234567890",
	})
	// ok: auth.go.jwt.hardcoded-secret
	return token.SignedString([]byte(os.Getenv("JWT_SECRET")))
}

func signFromVar(secret []byte) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
		"sub": "1234567890",
	})
	// ok: auth.go.jwt.hardcoded-secret
	return token.SignedString(secret)
}

func parseFromEnvKeyfunc(tokenString string) (*jwt.Token, error) {
	return jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
		// ok: auth.go.jwt.hardcoded-secret
		return []byte(os.Getenv("JWT_SECRET")), nil
	})
}

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

// oauthlint-disable-next-line auth.go.jwt.hardcoded-secret -- <reason>

References

https://pkg.go.dev/github.com/golang-jwt/jwt/v5#Token.SignedString ↗https://cwe.mitre.org/data/definitions/798.html ↗