{"record":{"id":"7e38dddc3af8df79","repo":"Tencent/WeKnora","slug":"missing-external-user-id-header","errorCode":null,"errorMessage":"missing external user id header","messagePattern":"missing external user id header","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/middleware/auth.go","lineNumber":30,"sourceCode":"\t\"time\"\n\n\t\"github.com/Tencent/WeKnora/internal/config\"\n\t\"github.com/Tencent/WeKnora/internal/logger\"\n\t\"github.com/Tencent/WeKnora/internal/types\"\n\t\"github.com/Tencent/WeKnora/internal/types/interfaces\"\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/golang-jwt/jwt/v5\"\n)\n\nconst (\n\tdefaultExternalUserIDHeader    = \"X-External-User-ID\"\n\tdefaultExternalUserTokenHeader = \"X-External-User-Token\"\n\tmaxExternalUserIDLen           = 128\n\tmaxExternalUserTokenTTL        = 24 * time.Hour\n)\n\nvar (\n\terrMissingDirectHeader      = errors.New(\"missing external user id header\")\n\terrInvalidExternalUserID    = errors.New(\"invalid external user id\")\n\terrInvalidExternalUserToken = errors.New(\"invalid external user token\")\n)\n\n// 无需认证的API列表\nvar noAuthAPI = map[string][]string{\n\t\"/health\":                 {\"GET\"},\n\t\"/api/v1/auth/register\":   {\"POST\"},\n\t\"/api/v1/auth/login\":      {\"POST\"},\n\t\"/api/v1/auth/auto-setup\": {\"POST\"},\n\t// Share-link surfaces accept a plaintext invite token from anonymous\n\t// callers (an invitee who hasn't registered yet). They are registered\n\t// as public routes in RegisterAuthRoutes and rate-limited by IP, so the\n\t// global Auth middleware must let them through — otherwise opening a\n\t// share link while logged out 401s and the frontend bounces the user to\n\t// /login instead of the register page (issue #1617).\n\t\"/api/v1/auth/invitations/lookup\": {\"POST\"},\n\t\"/api/v1/auth/register-by-invite\": {\"POST\"},","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/middleware/auth.go#L12-L48","documentation":"errMissingDirectHeader is returned by resolveAPIPrincipal when the API auth mode requires the X-External-User-ID header (cfg.RequireDirectHeader) but the request does not carry it. It is a sentinel guard on incoming request headers, converted by apiPrincipalAuthErrorMessage to an 'Unauthorized: missing external user id header' response.","triggerScenarios":"Thrown at internal/middleware/auth.go:30 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Client must send the X-External-User-ID header on API requests","If the header is optional, disable RequireDirectHeader in config so the fallback principal is used","Check proxy/gateway config is not stripping the custom header"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}