{"record":{"id":"e9707a2bbfe124b1","repo":"github/github-mcp-server","slug":"bad-request-authorization-header-is-badly-formatt","errorCode":null,"errorMessage":"bad request: Authorization header is badly formatted","messagePattern":"bad request: Authorization header is badly formatted","errorType":"http","errorClass":"utils.ErrBadAuthorizationHeader","httpStatus":400,"severity":"error","filePath":"pkg/http/middleware/token.go","lineNumber":34,"sourceCode":"\t\t\tctx := r.Context()\n\n\t\t\t// Check if token info already exists in context, if it does, skip extraction.\n\t\t\t// In remote setup, we may have already extracted token info earlier.\n\t\t\tif _, ok := ghcontext.GetTokenInfo(ctx); ok {\n\t\t\t\t// Token info already exists in context, skip extraction\n\t\t\t\tnext.ServeHTTP(w, r)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttokenType, token, err := utils.ParseAuthorizationHeader(r)\n\t\t\tif err != nil {\n\t\t\t\t// For missing Authorization header, return 401 with WWW-Authenticate header per MCP spec\n\t\t\t\tif errors.Is(err, utils.ErrMissingAuthorizationHeader) {\n\t\t\t\t\tsendAuthChallenge(w, r, oauthCfg)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// For other auth errors (bad format, unsupported), return 400\n\t\t\t\thttp.Error(w, err.Error(), http.StatusBadRequest)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tctx = ghcontext.WithTokenInfo(ctx, &ghcontext.TokenInfo{\n\t\t\t\tToken:     token,\n\t\t\t\tTokenType: tokenType,\n\t\t\t})\n\t\t\tr = r.WithContext(ctx)\n\n\t\t\tnext.ServeHTTP(w, r)\n\t\t})\n\t}\n}\n\n// sendAuthChallenge sends a 401 Unauthorized response with WWW-Authenticate header\n// containing the OAuth protected resource metadata URL as per RFC 6750 and MCP spec.\nfunc sendAuthChallenge(w http.ResponseWriter, r *http.Request, oauthCfg *oauth.Config) {\n\tresourcePath := oauth.ResolveResourcePath(r, oauthCfg)","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/pkg/http/middleware/token.go#L16-L52","documentation":"This is the 400 response the token middleware writes via http.Error(w, err.Error(), 400) when ParseAuthorizationHeader fails with a non-missing-header problem and the rendered text is 'bad request: Authorization header is badly formatted' - the mark.ErrBadRequest prefix ('bad request') plus the sentinel from pkg/utils/token.go. Concretely: the header was present, but the token matched no supported GitHub format (ghp_, github_pat_, gho_, ghu_, ghs_, or legacy 40-hex).","triggerScenarios":"Authorization: Bearer <token> where the token is a placeholder, another vendor's credential, an unexpanded ${GITHUB_TOKEN} literal, or otherwise prefix-unknown.","commonSituations":"Example tokens left in committed configs; env interpolation failing in CI so the literal placeholder is sent; tokens truncated by column limits when copied out of logs/secrets.","solutions":["Log a safe prefix (first 4 chars) of the token being sent to confirm which value reaches the server","Replace with a supported GitHub token type (ghp_/github_pat_/gho_/ghu_/ghs_)","Verify secret interpolation - an unexpanded ${VAR} or $VAR literal in the value is a classic cause"],"exampleFix":"# before\nAuthorization: Bearer ${GITHUB_TOKEN}   # unexpanded placeholder\n\n# after\nAuthorization: Bearer ghp_xxxx           # properly interpolated real token","handlingStrategy":"validation","validationCode":"var gitHubTokenRe = regexp.MustCompile(`^(ghp_|github_pat_|gho_|ghu_|ghs_)[A-Za-z0-9_]+$|^[a-f0-9]{40}$`)\n\nif !gitHubTokenRe.MatchString(token) {\n\treturn errors.New(\"token does not look like a GitHub token; server will answer 400 badly formatted\")\n}\nreq.Header.Set(\"Authorization\", \"Bearer \"+token)","typeGuard":"func isBadAuthHeader(err error) bool {\n\treturn errors.Is(err, utils.ErrBadAuthorizationHeader)\n}","tryCatchPattern":"// middleware shape: distinguish the three auth sentinels before choosing a status\nif err != nil {\n\tswitch {\n\tcase errors.Is(err, utils.ErrMissingAuthorizationHeader):\n\t\tsendAuthChallenge(w, r) // 401 + WWW-Authenticate\n\tcase errors.Is(err, utils.ErrBadAuthorizationHeader), errors.Is(err, utils.ErrUnsupportedAuthorizationHeader):\n\t\thttp.Error(w, err.Error(), http.StatusBadRequest)\n\t}\n}","preventionTips":["Verify secret interpolation actually expanded before the request leaves CI","Log a safe token prefix (first 4 chars) client-side to catch placeholder leaks","Distinguish 400 (fix the token) from 401 (run the OAuth flow) in error handling"],"tags":["http","authentication","token","middleware","configuration"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}