{"record":{"id":"e0a8a3e895c5c2ba","repo":"we-promise/sure","slug":"unauthorized-e0a8a3","errorCode":"unauthorized","errorMessage":"Authentication token missing in response","messagePattern":"Authentication token missing in response","errorType":"exception","errorClass":"AuthenticationError","httpStatus":null,"severity":"error","filePath":"app/models/provider/indexa_capital.rb","lineNumber":187,"sourceCode":"    end\n\n    def token\n      @token ||= token_auth? ? @api_token : authenticate!\n    end\n\n    def authenticate!\n      response = self.class.post(\n        \"#{base_url}/auth/authenticate\",\n        headers: base_headers,\n        body: {\n          username: username,\n          document: document,\n          password: password\n        }.to_json\n      )\n      payload = handle_response(response)\n      jwt = payload[:token]\n      raise AuthenticationError.new(\"Authentication token missing in response\", :unauthorized) if jwt.blank?\n\n      jwt\n    end\n\n    def handle_response(response)\n      case response.code\n      when 200, 201\n        begin\n          JSON.parse(response.body, symbolize_names: true)\n        rescue JSON::ParserError => e\n          raise Error.new(\"Invalid JSON in response: #{e.message}\", :bad_response)\n        end\n      when 400\n        Rails.logger.error \"IndexaCapital API: Bad request - #{response.body}\"\n        raise Error.new(\"Bad request: #{response.body}\", :bad_request)\n      when 401\n        raise AuthenticationError.new(\"Invalid credentials\", :unauthorized)\n      when 403","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/indexa_capital.rb#L169-L205","documentation":"POST /auth/authenticate returned 200/201 with parseable JSON, but payload[:token] is blank. This only happens in username/document/password mode - when an api_token is configured, token_auth? is true and authenticate! is never called (token = api_token directly). It means authentication 'succeeded' at HTTP level but the response envelope does not contain a usable JWT.","triggerScenarios":"Indexa changes the auth response shape (token renamed or nested); the account is in a state that returns 200 with an error-ish body but no token (e.g. re-login required, 2FA introduced); an intermediate gateway rewriting the response.","commonSituations":"Silent API contract changes after Indexa deploys, credentials technically valid but account locked pending re-acceptance of terms, password-mode integrations breaking while token-mode ones keep working.","solutions":["Switch to api_token mode: generate a token from the Indexa dashboard/env and pass api_token: - it bypasses authenticate! entirely","Log payload.keys on failure to detect envelope changes immediately","Verify the triple manually (username / document / password) against a curl POST to /auth/authenticate","If the shape changed, update the jwt = payload[:token] extraction to the new field and add a regression test"],"exampleFix":"# before\nProvider::IndexaCapital.new(username: u, document: d, password: p)\n\n# after\nProvider::IndexaCapital.new(api_token: credentials.api_token.presence || begin\n  Provider::IndexaCapital.new(username: u, document: d, password: p).tap(&:token)\nend)\n# simpler: just prefer the pre-generated token\nProvider::IndexaCapital.new(api_token: settings.indexa_api_token)","handlingStrategy":"fallback","validationCode":"# prefer token mode: it never calls authenticate!, so this error cannot occur\nclient = if settings.indexa_api_token.present?\n  Provider::IndexaCapital.new(api_token: settings.indexa_api_token.to_s.strip)\nelse\n  Provider::IndexaCapital.new(username: u, document: d, password: p)\nend","typeGuard":"def indexa_token_missing?(error)\n  error.is_a?(Provider::IndexaCapital::AuthenticationError) &&\n    error.message == \"Authentication token missing in response\"\nend","tryCatchPattern":"begin\n  client.list_accounts\nrescue Provider::IndexaCapital::AuthenticationError => e\n  raise unless e.message == \"Authentication token missing in response\"\n  raise unless settings.indexa_api_token.present? # fallback available?\n  Provider::IndexaCapital.new(api_token: settings.indexa_api_token).list_accounts\nend","preventionTips":["Default to api_token mode; username/password mode is the fragile path","Contract-test the auth endpoint (payload includes :token) in CI to catch envelope changes","Log payload.keys when token extraction fails - it identifies renames instantly","Rotate to a dashboard token as the immediate mitigation whenever this fires"],"tags":["indexa-capital","authentication","jwt","response-contract","credential-mode"],"backgroundTag":"auth-token-missing","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}