hashicorp/nomad · error
unable to parse public key for JWT auth: %v
Error message
unable to parse public key for JWT auth: %v
What it means
usingStaticKeys wraps jwt.ParsePublicKeyPEM failures: one of the public keys configured on the auth method (RSAPublicKey or JWKSCACert-style static key list) could not be parsed as a valid PEM-encoded public key. The wrapped underlying error (usually go-jose's asn1/pem parse error) identifies the exact key that failed.
Source
Thrown at lib/auth/jwt/validator.go:95
)
}
if iss, ok := claims["iss"].(string); !ok {
return nil, fmt.Errorf("unable to read iss property of provided token")
} else if !slices.Contains(methodConf.BoundIssuer, iss) {
return nil, fmt.Errorf("invalid JWT issuer: %v", claims["iss"])
}
}
return claims, nil
}
func usingStaticKeys(keys []string) (jwt.KeySet, error) {
var parsedKeys []crypto.PublicKey
for _, v := range keys {
key, err := jwt.ParsePublicKeyPEM([]byte(v))
parsedKeys = append(parsedKeys, key)
if err != nil {
return nil, fmt.Errorf("unable to parse public key for JWT auth: %v", err)
}
}
return jwt.NewStaticKeySet(parsedKeys)
}
func usingJWKS(ctx context.Context, jwksurl, jwkscapem string) (jwt.KeySet, error) {
// Measure the JWKS endpoint performance.
defer metrics.MeasureSince([]string{"nomad", "acl", "jwt", "jwks"}, time.Now())
keySet, err := jwt.NewJSONWebKeySet(ctx, jwksurl, jwkscapem)
if err != nil {
return nil, fmt.Errorf("unable to get validation keys from JWKS: %v", err)
}
return keySet, nil
}
func usingOIDC(ctx context.Context, oidcurl string, oidccapem []string) (jwt.KeySet, error) {
// Measure the OIDC endpoint performance.View on GitHub (pinned to 482b49bf1a)
Solutions
- Check each configured key has valid PEM headers/footers (`-----BEGIN PUBLIC KEY-----` / `-----END PUBLIC KEY-----`) and intact newlines; re-paste the key.
- Ensure you pasted a PUBLIC key, not the private key or the X.509 certificate; extract with `openssl rsa -in key.pem -pubout`.
- Inspect the wrapped %v error — asn1 errors usually mean wrong key type or corrupted base64.
Example fix
// before: private key in config
RSAPublicKeys: []string{"-----BEGIN RSA PRIVATE KEY-----\n..."}
// after: public key with clean PEM
RSAPublicKeys: []string{"-----BEGIN PUBLIC KEY-----\nMIIBIjANBg...\n-----END PUBLIC KEY-----"} Defensive patterns
Strategy: validation
Validate before calling
// validate every configured key parses before writing the auth method
for i, k := range keys {
if _, err := jwt.ParsePublicKeyPEM([]byte(k)); err != nil {
return fmt.Errorf("RSAPublicKeys[%d] invalid: %w", i, err)
}
} Type guard
func isPEMPublicKey(s string) bool {
blk, _ := pem.Decode([]byte(s))
return blk != nil && strings.Contains(blk.Type, "PUBLIC KEY")
} Try / catch
keyset, err := usingStaticKeys(keys)
if err != nil {
return fmt.Errorf("auth method key config invalid; check each RSAPublicKeys entry is a public PEM: %w", err)
} Prevention
- Round-trip keys through `openssl pkey -pubin -in key.pem -noout` before uploading.
- Never paste private keys or certificates into RSAPublicKeys.
- Preserve newlines when pasting into UIs or JSON configs (escape as \n).
When it happens
Trigger: Validate → keyset construction when the auth method uses static keys (JWTAuthMethodConfig with RSAPublicKeys and no JWKS/OIDC URL) and any entry is not parseable PEM.
Common situations: Pasted key missing the BEGIN/END PEM headers or with broken line endings; a private key pasted where a public key is expected; cert (X.509) pasted instead of a public key; secrets UI stripped newlines.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- no signed workload identity available
- JWT login returned an empty secret
- JWT login did not return a token
- unable to verify signature of JWT token: %v
- auth method specifies BoundIssuers but the provided token do
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/3beedbfd8d4aed91.
Report an issue: GitHub.