phacility/phabricator · error · Exception

Expected '%s' to be '%s'!

Error message

Expected '%s' to be '%s'!

What it means

Thrown during the OAuth 1.0a request-token step of getAuthenticateURI(): the adapter POSTs to the provider's request token URI, parses the body as an HTTP query string, and requires oauth_callback_confirmed to be exactly the string 'true', as mandated by RFC 5849 section 2.1. If the provider omits the parameter or returns any other value (including a parsed-HTML garbage body where idx() finds nothing), the handshake is aborted before the user is ever redirected to the provider.

Source

Thrown at src/applications/auth/adapter/PhutilOAuth1AuthAdapter.php:150

    return $future;
  }

  public function getClientRedirectURI() {
    $request_token_uri = $this->getRequestTokenURI();

    $future = $this->newOAuth1Future($request_token_uri);
    if (strlen($this->getCallbackURI())) {
      $future->setCallbackURI($this->getCallbackURI());
    }

    list($body) = $future->resolvex();
    $data = id(new PhutilQueryStringParser())->parseQueryString($body);

    // NOTE: Per the spec, this value MUST be the string 'true'.
    $confirmed = idx($data, 'oauth_callback_confirmed');
    if ($confirmed !== 'true') {
      throw new Exception(
        pht("Expected '%s' to be '%s'!", 'oauth_callback_confirmed', 'true'));
    }

    $this->readTokenAndTokenSecret($data);

    $authorize_token_uri = new PhutilURI($this->getAuthorizeTokenURI());
    $authorize_token_uri->replaceQueryParam('oauth_token', $this->getToken());

    return phutil_string_cast($authorize_token_uri);
  }

  protected function finishOAuthHandshake() {
    $this->willFinishOAuthHandshake();

    if (!$this->getToken()) {
      throw new Exception(pht('Expected token to finish OAuth handshake!'));
    }
    if (!$this->getVerifier()) {

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Verify the request token URI returned by getRequestTokenURI() is the provider's OAuth 1.0a endpoint, not a legacy OAuth 1.0 one.
  2. Reproduce the request manually (curl with a signed oauth_callback) and inspect the raw response body to see exactly what the provider returned.
  3. Confirm the provider supports OAuth 1.0a with callbacks; if it only supports OAuth 1.0, the handshake cannot pass this check and needs a different adapter strategy.
  4. Make sure setCallbackURI() was called with a valid callback before getAuthenticateURI() so the provider confirms it.

Example fix

// before: adapter points at a legacy OAuth 1.0 endpoint that never confirms callbacks
protected function getRequestTokenURI() {
  return 'https://provider.tld/oauth/request';
}

// after: use the OAuth 1.0a endpoint per RFC 5849
protected function getRequestTokenURI() {
  return 'https://provider.tld/oauth1a/request';
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check provider config before starting the handshake
if (!strlen($adapter->getRequestTokenURI())) {
  throw new PhutilAuthConfigurationException('request token URI missing');
}
if (!strlen($adapter->getCallbackURI())) {
  throw new PhutilAuthConfigurationException('callback URI missing');
}

Try / catch

try {
  $uri = $adapter->getAuthenticateURI();
} catch (Exception $ex) {
  // Log the provider/endpoint context; the message names the missing param.
  phlog($ex);
  return $this->newDialog()->setTitle(pht('Authentication Failed'))
    ->appendParagraph($ex->getMessage());
}

Prevention

When it happens

Trigger: Calling getAuthenticateURI() on a PhutilOAuth1AuthAdapter subclass when: the provider implements plain OAuth 1.0 (which has no callback confirmation) instead of 1.0a; the configured request token URI is wrong and returns an HTML error page that parseQueryString() turns into an array without 'oauth_callback_confirmed'; the provider rejects the application and returns a 200 body such as 'oauth_problem=parameter_absent'; or no callback URI was set so the provider never echoes confirmation.

Common situations: Misconfigured request-token endpoint URL in a custom provider adapter; a provider that ignores the oauth_callback parameter; an intermediate proxy or login wall returning HTML instead of the token body; migrating a legacy OAuth 1.0 integration to 1.0a.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/b925c09d45f4052b. Report an issue: GitHub.