phacility/phabricator · error · Exception

Expected ' ' to be ' '!

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.

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.

Appendix: 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)