{"record":{"id":"b985680eed546d1b","repo":"phacility/phabricator","slug":"duo-api-hostname-s-is-invalid-hostname-must","errorCode":null,"errorMessage":"Duo API hostname (\"%s\") is invalid, hostname must be \"*.duosecurity.com\".","messagePattern":"Duo API hostname \\(\"(.+?)\"\\) is invalid, hostname must be \"\\*\\.duosecurity\\.com\"\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/auth/factor/PhabricatorDuoAuthFactor.php","lineNumber":812,"sourceCode":"\n  private function newDuoConfig(PhabricatorUser $user, $duo_user) {\n    $config_properties = array(\n      'duo.username' => $duo_user,\n    );\n\n    $config = $this->newConfigForUser($user)\n      ->setFactorName(pht('Duo (%s)', $duo_user))\n      ->setProperties($config_properties);\n\n    return $config;\n  }\n\n  public static function requireDuoAPIHostname($hostname) {\n    if (preg_match('/\\.duosecurity\\.com\\z/', $hostname)) {\n      return;\n    }\n\n    throw new Exception(\n      pht(\n        'Duo API hostname (\"%s\") is invalid, hostname must be '.\n        '\"*.duosecurity.com\".',\n        $hostname));\n  }\n\n  public function newChallengeStatusView(\n    PhabricatorAuthFactorConfig $config,\n    PhabricatorAuthFactorProvider $provider,\n    PhabricatorUser $viewer,\n    PhabricatorAuthChallenge $challenge) {\n\n    $duo_xaction = $challenge->getChallengeKey();\n\n    $parameters = array(\n      'txid' => $duo_xaction,\n    );\n","sourceCodeStart":794,"sourceCodeEnd":830,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/auth/factor/PhabricatorDuoAuthFactor.php#L794-L830","documentation":"PhabricatorDuoAuthFactor::requireDuoAPIHostname() enforces that the provider's API hostname ends in '.duosecurity.com' (regex '/\\.duosecurity\\.com\\z/'). Duo API endpoints always live at api-<id>.duosecurity.com, so a failing value is treated as misconfiguration. It is invoked both when saving the provider (PhabricatorAuthFactorProviderDuoHostnameTransaction) and on every Duo API call via newDuoFuture(), so bad values are rejected at save time and at runtime.","triggerScenarios":"Setting duo.hostname to anything not ending in .duosecurity.com: 'https://api-xxxx.duosecurity.com' (scheme prefix), 'api-xxxx.duosecurity.com/' (trailing slash), 'api-xxxx.duo.com' (wrong domain), or pasting the SSO/admin hostname instead of the API hostname.","commonSituations":"Copying the wrong value from the Duo integration page; adding protocol or path by habit; attempting to point the factor at a corporate proxy hostname, which this factor does not support.","solutions":["Copy the 'API hostname' exactly from the Duo integration details (e.g. api-1a2b3c4d.duosecurity.com) — no scheme, no trailing slash.","Strip any 'https://' prefix or trailing '/' from the stored value.","Ensure direct egress to *.duosecurity.com from the web host; alternate proxy hostnames are not supported."],"exampleFix":"// before: provider config 'Duo API Hostname'\nhttps://api-1a2b3c4d.duosecurity.com/\n// after\napi-1a2b3c4d.duosecurity.com","handlingStrategy":"validation","validationCode":"// Normalize and validate before saving or calling the API.\n$hostname = rtrim(trim($provider->getAuthFactorProviderProperty(\n  PhabricatorDuoAuthFactor::PROP_HOSTNAME)), '/');\nif (!preg_match('/\\.duosecurity\\.com\\z/', $hostname)) {\n  // fix the value (strip scheme, correct the domain) before proceeding\n}\nPhabricatorDuoAuthFactor::requireDuoAPIHostname($hostname);","typeGuard":"function isDuoApiHostname($hostname) {\n  return is_string($hostname)\n    && preg_match('/\\.duosecurity\\.com\\z/', $hostname) === 1;\n}","tryCatchPattern":null,"preventionTips":["Paste the API hostname from the Duo integration page verbatim.","Never include a scheme or path; the client appends them.","Reuse the public static requireDuoAPIHostname() in provider-save validation so bad values never reach runtime.","This factor cannot use proxy hostnames — ensure direct *.duosecurity.com egress."],"tags":["duo","hostname","provider-config","phabricator"],"backgroundTag":"invalid-hostname","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}