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
- Verify the request token URI returned by getRequestTokenURI() is the provider's OAuth 1.0a endpoint, not a legacy OAuth 1.0 one.
- Reproduce the request manually (curl with a signed oauth_callback) and inspect the raw response body to see exactly what the provider returned.
- 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.
- 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
- Verify provider endpoints with a manual signed request before shipping an adapter.
- Only integrate OAuth 1.0a providers; plain OAuth 1.0 cannot pass the callback confirmation check.
- Always set a concrete callback URI on the adapter before getAuthenticateURI().
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
- Expected token to finish OAuth handshake!
- Expected verifier to finish OAuth handshake!
- Expected '%s' in response!
- Access token error: %s
- Failed to decode OAuth access token response: %s
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/b925c09d45f4052b.
Report an issue: GitHub.