dgraph-io/dgraph · error
kid not present in JWT
Error message
kid not present in JWT
What it means
The JWT key-lookup callback runs for every token parsed against a JWK URL set. It requires a `kid` (key ID) header so it can select the correct public key from the fetched JWK set. If the token's header has no `kid`, the library cannot pick a key and rejects the token with this message. It is surfaced to the caller wrapped as "unable to parse jwt token:...".
Source
Thrown at graphql/authorization/auth.go:359
// JWKUrl.
func (a *AuthMeta) validateThroughJWKUrl(jwtStr string) (*jwt.Token, error) {
var err error
var token *jwt.Token
for i := range a.JWKUrls {
if a.isExpired(i) {
err = a.refreshJWK(i)
if err != nil {
return nil, errors.Wrap(err, "while refreshing JWK from the URL")
}
}
token, err = jwt.ParseWithClaims(
jwtStr,
&CustomClaims{authMeta: a},
func(token *jwt.Token) (interface{}, error) {
kid := token.Header["kid"]
if kid == nil {
return nil, errors.Errorf("kid not present in JWT")
}
signingKeys := a.jwkSet[i].Key(kid.(string))
if len(signingKeys) == 0 {
return nil, errors.Errorf("Invalid kid")
}
return signingKeys[0].Key, nil
},
)
if err == nil {
return token, nil
}
}
return nil, err
}
func (a *AuthMeta) validateJWTCustomClaims(jwtStr string) (*CustomClaims, error) {View on GitHub (pinned to 759e242be6)
Solutions
- Fix the token issuer so it includes a kid header matching an entry in the JWK set.
- If only one key is used, consider static-key verification (set Algo + VerificationKey instead of JWKUrls).
- Verify you are validating tokens from the correct issuer/environment.
- Decode the token header (base64 of the first dot-separated segment) to confirm kid is truly missing.
- Pin/upgrade the signing library at the issuer to one that sets kid.
Example fix
// issuer side: before token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) // after token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) token.Header["kid"] = "my-key-id-2024"
Defensive patterns
Strategy: validation
Validate before calling
func tokenHasKid(jwtStr string) bool {
parts := strings.Split(jwtStr, ".")
if len(parts) != 3 { return false }
hdr, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil { return false }
var h map[string]interface{}
if json.Unmarshal(hdr, &h) != nil { return false }
_, ok := h["kid"].(string)
return ok
} Type guard
func hasString(v map[string]interface{}, key string) (string, bool) {
s, ok := v[key].(string)
return s, ok && s != ""
} Try / catch
if _, err := auth.ExtractCustomClaims(ctx, jwtStr); err != nil && strings.Contains(err.Error(), "kid not present") {
return nil, status.Error(codes.Unauthenticated, "token missing kid header; obtain a token from a compliant issuer")
} Prevention
- Ensure your IdP/signer always includes kid in the token header
- Validate token headers in CI with a sample token from your issuer
- Reject non-kid tokens early at the gateway with a clear message
- Document the kid requirement for internal token issuers
When it happens
Trigger: jwt.ParseWithClaims invokes the keyfunc; token.Header["kid"] is nil because the JWT issuer signed the token without embedding a kid header, or the token is malformed/手工 crafted.
Common situations: Using an IdP or token signer configured to omit kid (common with single-key HS256 signers); token produced by an older service or library version that omits kid; testing with hand-rolled tokens; wrong endpoint issuing tokens from a different signer configuration.
Related errors
- while refreshing JWK from the URL
- Invalid kid
- expecting either JWKUrl or JWKUrls, both were given
- expecting either JWKUrl/JWKUrls or (VerificationKey, Algo),
- required field missing in Dgraph.Authorization:%s
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/b9b30cb26dfafd47.
Report an issue: GitHub.