{"record":{"id":"41a9c1f2b4408266","repo":"we-promise/sure","slug":"unauthorized","errorCode":"unauthorized","errorMessage":"Invalid Brex API token or account permissions","messagePattern":"Invalid Brex API token or account permissions","errorType":"http","errorClass":"Provider::Brex::BrexError","httpStatus":401,"severity":"error","filePath":"app/models/provider/brex.rb","lineNumber":215,"sourceCode":"      {\n        \"Authorization\" => \"Bearer #{token}\",\n        \"Content-Type\" => \"application/json\",\n        \"Accept\" => \"application/json\"\n      }\n    end\n\n    def handle_response(response, path:)\n      trace_id = brex_trace_id(response)\n\n      case response.code\n      when 200\n        parse_json(response.body)\n      when 400\n        Rails.logger.error \"Brex API: bad request for #{path} trace_id=#{trace_id}\"\n        raise BrexError.new(\"Bad request to Brex API\", :bad_request, http_status: 400, trace_id: trace_id)\n      when 401\n        Rails.logger.warn \"Brex API: unauthorized for #{path} trace_id=#{trace_id}\"\n        raise BrexError.new(\"Invalid Brex API token or account permissions\", :unauthorized, http_status: 401, trace_id: trace_id)\n      when 403\n        Rails.logger.warn \"Brex API: access forbidden for #{path} trace_id=#{trace_id}\"\n        raise BrexError.new(\"Access forbidden - check Brex API token scopes\", :access_forbidden, http_status: 403, trace_id: trace_id)\n      when 404\n        Rails.logger.warn \"Brex API: resource not found for #{path} trace_id=#{trace_id}\"\n        raise BrexError.new(\"Brex resource not found\", :not_found, http_status: 404, trace_id: trace_id)\n      when 429\n        Rails.logger.warn \"Brex API: rate limited for #{path} trace_id=#{trace_id}\"\n        raise BrexError.new(\"Brex rate limit exceeded. Please try again later.\", :rate_limited, http_status: 429, trace_id: trace_id)\n      else\n        Rails.logger.error \"Brex API: unexpected response code=#{response.code} path=#{path} trace_id=#{trace_id}\"\n        raise BrexError.new(\"Failed to fetch data from Brex API: HTTP #{response.code}\", :fetch_failed, http_status: response.code, trace_id: trace_id)\n      end\n    end\n\n    def parse_json(body)\n      return {} if body.blank?\n","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/brex.rb#L197-L233","documentation":"Raised by Provider::Brex#handle_response on HTTP 401: the Bearer token sent in auth_headers was rejected by Brex, so every endpoint call will fail the same way. The token is taken verbatim from the Provider::Brex constructor (stripped of whitespace) and never refreshed by this client. http_status 401 and the X-Brex-Trace-Id are attached to the error.","triggerScenarios":"The stored token was revoked or expired in the Brex dashboard; a staging token is used against https://api.brex.com (or vice versa); the token was truncated or mangled when copied; an empty/placeholder token was passed to Provider::Brex.new.","commonSituations":"Rotating API credentials and forgetting to update the encrypted store, environment mismatch between token and base_url, whitespace or newline contamination from copy-paste or .env handling.","solutions":["Issue a fresh API token in the Brex dashboard and update the stored credential","Verify the token matches the environment: staging tokens only work with base_url https://api-staging.brex.com","Confirm the token has no surrounding whitespace/newlines (the constructor strips edges, but internal characters must be intact)","Check the Rails log 'Brex API: unauthorized for <path> trace_id=...' and confirm the same failure across all endpoints (a 401 on only one endpoint is actually a scopes problem, see :access_forbidden)"],"exampleFix":"# before\nProvider::Brex.new(ENV[\"BREX_TOKEN\"].to_s) # nil -> \"\" silently, fails later with 401\n\n# after\ntoken = ENV[\"BREX_TOKEN\"].to_s.strip\nraise ArgumentError, \"BREX_TOKEN is missing or empty\" if token.empty?\nProvider::Brex.new(token)","handlingStrategy":"validation","validationCode":"def brex_token_configured?(token)\n  token.is_a?(String) && !token.strip.empty?\nend","typeGuard":"def brex_unauthorized?(error)\n  error.is_a?(Provider::Brex::BrexError) && error.error_type == :unauthorized\nend","tryCatchPattern":"begin\n  client.get_cash_accounts\nrescue Provider::Brex::BrexError => e\n  raise unless e.error_type == :unauthorized\n  connection.update!(status: \"reauth_required\") # never retry; flag for credential rotation\n  raise\nend","preventionTips":["Validate token presence at client construction instead of failing on first API call","Match environment: staging token with STAGING_BASE_URL only","Store tokens encrypted and rotate on a schedule; monitor for revocation","Run a cheap get_cash_accounts canary after credential changes"],"tags":["brex","http-401","authentication","api-token"],"backgroundTag":"api-token-invalid","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}