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

  1. Check each configured key has valid PEM headers/footers (`-----BEGIN PUBLIC KEY-----` / `-----END PUBLIC KEY-----`) and intact newlines; re-paste the key.
  2. Ensure you pasted a PUBLIC key, not the private key or the X.509 certificate; extract with `openssl rsa -in key.pem -pubout`.
  3. 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

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

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/3beedbfd8d4aed91. Report an issue: GitHub.