{"record":{"id":"d5365c273f514a0b","repo":"dgraph-io/dgraph","slug":"unexpected-signing-method-in-token-v","errorCode":null,"errorMessage":"unexpected signing method in token: %v","messagePattern":"unexpected signing method in token: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/jwt_helper.go","lineNumber":36,"sourceCode":")\n\n// MaybeKeyToBytes converts the x.Sensitive type into []byte if the type of interface really\n// is x.Sensitive. We keep the type x.Sensitive for private and public keys so that it\n// doesn't get printed into the logs but the type the JWT library needs is []byte.\nfunc MaybeKeyToBytes(k interface{}) interface{} {\n\tif kb, ok := k.(Sensitive); ok {\n\t\treturn []byte(kb)\n\t}\n\treturn k\n}\n\nfunc ParseJWT(jwtStr string) (jwt.MapClaims, error) {\n\ttoken, err := jwt.Parse(jwtStr, func(token *jwt.Token) (interface{}, error) {\n\t\tif WorkerConfig.AclJwtAlg == nil {\n\t\t\treturn nil, errors.Errorf(\"ACL is disabled\")\n\t\t}\n\t\tif token.Method.Alg() != WorkerConfig.AclJwtAlg.Alg() {\n\t\t\treturn nil, errors.Errorf(\"unexpected signing method in token: %v\", token.Header[\"alg\"])\n\t\t}\n\t\treturn MaybeKeyToBytes(WorkerConfig.AclPublicKey), nil\n\t})\n\tif err != nil {\n\t\t// This is for backward compatibility in clients\n\t\tif errors.Is(err, jwt.ErrTokenExpired) {\n\t\t\terr = errors.Wrap(errTokenExpired, jwt.ErrTokenInvalidClaims.Error())\n\t\t}\n\t\treturn nil, errors.Wrapf(err, \"unable to parse jwt token\")\n\t}\n\n\tclaims, ok := token.Claims.(jwt.MapClaims)\n\tif !ok || !token.Valid {\n\t\treturn nil, errors.Errorf(\"claims in jwt token is not map claims\")\n\t}\n\treturn claims, nil\n}\n","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/x/jwt_helper.go#L18-L54","documentation":"The key-lookup callback in jwt.Parse rejects tokens whose header 'alg' does not match the configured ACL algorithm (WorkerConfig.AclJwtAlg.Alg()). This is an algorithm-confusion defense: a token signed with a different (possibly weaker) algorithm must not be accepted. The error includes the token's alg header value.","triggerScenarios":"jwt.Parse is given a token whose alg header (e.g. RS256, none, HS256) differs from WorkerConfig.AclJwtAlg.Alg() — e.g. client signs JWTs with the wrong algorithm or a token from a different system is presented.","commonSituations":"Client side regenerated keys with a different alg after a server upgrade; mixing tokens from a non-ACL system; maliciously crafted tokens probing for algorithm confusion; config where server expects HS256 but clients use RS256.","solutions":["Re-issue the access JWT signed with the algorithm the server expects (match WorkerConfig.AclJwtAlg).","Align server config: set AclJwtAlg to the algorithm actually used to sign your tokens.","Check the token issuer/pipeline — ensure you are sending the ACL access token, not some other JWT.","Read the alg value in the error message and compare against your signing code's algorithm; fix whichever side is wrong."],"exampleFix":"// before: client signs with RS256 while server expects HS256\nalg := jwt.SigningMethodRS256\n// after: use the configured algorithm\ntok := jwt.NewWithClaims(WorkerConfig.AclJwtAlg, claims)","handlingStrategy":"validation","validationCode":"parts := strings.Split(token, \".\")\nif len(parts) != 3 { return errors.New(\"malformed jwt\") }\nhdr, _ := base64.RawURLEncoding.DecodeString(parts[0])\nvar h struct{ Alg string `json:\"alg\"` }\njson.Unmarshal(hdr, &h)\nif h.Alg != WorkerConfig.AclJwtAlg.Alg() {\n    return fmt.Errorf(\"token alg %s does not match configured %s\", h.Alg, WorkerConfig.AclJwtAlg.Alg())\n}","typeGuard":"func algMatches(token *jwt.Token) bool {\n    return WorkerConfig.AclJwtAlg != nil && token.Method.Alg() == WorkerConfig.AclJwtAlg.Alg()\n}","tryCatchPattern":null,"preventionTips":["Always sign client tokens with the same algorithm configured server-side (AclJwtAlg).","Never hardcode signing methods; read them from shared config.","Never accept 'alg: none' or let the token header choose the algorithm.","Add an integration test that mints a token and parses it with x.ParseJWT before deploys."],"tags":["jwt","algorithm","security","authentication"],"backgroundTag":"jwt-signing-method-mismatch","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}