{"record":{"id":"4239c867268234ff","repo":"phacility/phabricator","slug":"expected-s-in-response","errorCode":null,"errorMessage":"Expected '%s' in response!","messagePattern":"Expected '(.+?)' in response!","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/auth/adapter/PhutilOAuth1AuthAdapter.php","lineNumber":188,"sourceCode":"    }\n\n    $validate_uri = $this->getValidateTokenURI();\n    $params = array(\n      'oauth_verifier' => $this->getVerifier(),\n    );\n\n    list($body) = $this->newOAuth1Future($validate_uri, $params)->resolvex();\n    $data = id(new PhutilQueryStringParser())->parseQueryString($body);\n\n    $this->readTokenAndTokenSecret($data);\n\n    $this->handshakeData = $data;\n  }\n\n  private function readTokenAndTokenSecret(array $data) {\n    $token = idx($data, 'oauth_token');\n    if (!$token) {\n      throw new Exception(pht(\"Expected '%s' in response!\", 'oauth_token'));\n    }\n\n    $token_secret = idx($data, 'oauth_token_secret');\n    if (!$token_secret) {\n      throw new Exception(\n        pht(\"Expected '%s' in response!\", 'oauth_token_secret'));\n    }\n\n    $this->setToken($token);\n    $this->setTokenSecret($token_secret);\n\n    return $this;\n  }\n\n  /**\n   * Hook that allows subclasses to take actions before the OAuth handshake\n   * is completed.\n   */","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/auth/adapter/PhutilOAuth1AuthAdapter.php#L170-L206","documentation":"readTokenAndTokenSecret() parses every OAuth 1 token response (both the request-token step and the access-token step in finishOAuthHandshake()) and requires an oauth_token entry. If idx($data, 'oauth_token') is empty, the provider returned a 200 body that does not contain a token - typically an error payload, an HTML page, or a differently-formatted response that parseQueryString() could not map.","triggerScenarios":"The validate-token or request-token endpoint returns 200 with an error body (e.g. 'oauth_problem=...') instead of a token; the body is HTML or JSON, so query-string parsing yields no oauth_token; the consumer key/secret are wrong and the provider signals the error in the body rather than the HTTP status; the response format changed after a provider API upgrade.","commonSituations":"Bad consumer key or secret on a provider that returns 200 for signature failures; provider endpoint returning JSON instead of a query string; clock skew or signature method mismatch producing provider error pages; the provider renaming endpoints after a version bump.","solutions":["Log or inspect the raw response body ($body before parseQueryString) to see the provider's actual error message.","Verify the consumer key and consumer secret configured for the adapter.","Check getRequestTokenURI()/getValidateTokenURI() values against the provider's current documentation.","Confirm the adapter's signature method and timestamp handling match what the provider expects."],"exampleFix":"// before: the provider's error body is discarded and the exception is opaque\nlist($body) = $this->newOAuth1Future($validate_uri, $params)->resolvex();\n$data = id(new PhutilQueryStringParser())->parseQueryString($body);\n\n// after: surface the raw body when required parameters are missing\nlist($body) = $this->newOAuth1Future($validate_uri, $params)->resolvex();\n$data = id(new PhutilQueryStringParser())->parseQueryString($body);\nif (empty($data['oauth_token'])) {\n  throw new Exception(pht('Provider token response was: %s', $body));\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  $adapter->finishOAuthHandshake();\n} catch (Exception $ex) {\n  phlog(sprintf(\n    'OAuth1 token exchange failed for provider \"%s\": %s',\n    $provider_key,\n    $ex->getMessage()));\n  return $this->newDialog()\n    ->setTitle(pht('Authentication Failed'))\n    ->appendParagraph($ex->getMessage());\n}","preventionTips":["Capture and log the raw provider body when building custom adapters so failures are diagnosable.","Validate consumer key/secret against the provider's app console before enabling the provider.","Monitor provider API changelogs for endpoint or response-format changes."],"tags":["oauth1","authentication","handshake","response-parsing","php"],"backgroundTag":"oauth1-handshake-failed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}