{"record":{"id":"37d0e19d609f377a","repo":"phacility/phabricator","slug":"unable-to-load-duo-api-credential-s","errorCode":null,"errorMessage":"Unable to load Duo API credential (\"%s\").","messagePattern":"Unable to load Duo API credential \\(\"(.+?)\"\\)\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/auth/factor/PhabricatorDuoAuthFactor.php","lineNumber":733,"sourceCode":"            ->setIcon('fa-refresh', 'green ph-spin'));\n    }\n\n    return $result;\n  }\n\n  private function newDuoFuture(PhabricatorAuthFactorProvider $provider) {\n    $credential_phid = $provider->getAuthFactorProviderProperty(\n      self::PROP_CREDENTIAL);\n\n    $omnipotent = PhabricatorUser::getOmnipotentUser();\n\n    $credential = id(new PassphraseCredentialQuery())\n      ->setViewer($omnipotent)\n      ->withPHIDs(array($credential_phid))\n      ->needSecrets(true)\n      ->executeOne();\n    if (!$credential) {\n      throw new Exception(\n        pht(\n          'Unable to load Duo API credential (\"%s\").',\n          $credential_phid));\n    }\n\n    $duo_key = $credential->getUsername();\n    $duo_secret = $credential->getSecret();\n    if (!$duo_secret) {\n      throw new Exception(\n        pht(\n          'Duo API credential (\"%s\") has no secret key.',\n          $credential_phid));\n    }\n\n    $duo_host = $provider->getAuthFactorProviderProperty(\n      self::PROP_HOSTNAME);\n    self::requireDuoAPIHostname($duo_host);\n","sourceCodeStart":715,"sourceCodeEnd":751,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/auth/factor/PhabricatorDuoAuthFactor.php#L715-L751","documentation":"PhabricatorDuoAuthFactor::newDuoFuture() resolves the provider property 'duo.credentialPHID' through PassphraseCredentialQuery with the omnipotent user and needSecrets(true). If no Passphrase credential with that PHID exists (deleted, destroyed, or the property references nothing valid), the factor cannot build a Duo API future and throws before any API call. Every Duo operation for that provider (enrollment, preauth, challenge) then fails.","triggerScenarios":"Any Duo API operation on a provider whose stored credential PHID no longer resolves: the Passphrase credential was deleted or destroyed, the auth_factor_provider row was hand-edited or restored from a partial dump, or the provider was created against a credential that was later removed.","commonSituations":"Admin deletes or rotates the old Duo credential in Passphrase before re-pointing the MFA provider; partial database restore loses the passphrase_credential row; scripting provider properties directly instead of using the edit UI.","solutions":["Open Auth > Multi-Factor Auth, edit the Duo provider, and select an existing, non-destroyed Passphrase credential (username = Duo integration key, secret = Duo secret key).","If the original credential was destroyed, create a new password-type credential with both keys and re-select it on the provider.","After saving, verify by starting a test enrollment or issuing a Duo challenge.","Audit other MFA providers for references to the same deleted credential."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Run when saving the provider config, not at login time.\n$phid = $provider->getAuthFactorProviderProperty(\n  PhabricatorDuoAuthFactor::PROP_CREDENTIAL);\n$exists = (bool) id(new PassphraseCredentialQuery())\n  ->setViewer(PhabricatorUser::getOmnipotentUser())\n  ->withPHIDs(array($phid))\n  ->withIsDestroyed(false)\n  ->executeOne();\nif (!$exists) {\n  // block the save with a config error naming the missing credential\n}","typeGuard":null,"tryCatchPattern":"try {\n  $future = $factor->newDuoFuture($provider);\n} catch (Exception $ex) {\n  // surface 'provider misconfigured' to admins and skip this provider\n  // rather than hard-failing every MFA login\n  throw new PhutilProxyException(\n    pht('Duo provider is misconfigured, check its credential.'),\n    $ex);\n}","preventionTips":["Never delete a Passphrase credential an MFA provider references; rename or rotate instead.","Re-select the credential on the provider immediately after any rotation.","Validate the credential PHID (exists, not destroyed) when saving factor provider config.","Keep one Duo credential per provider and document the linkage."],"tags":["duo","passphrase-credential","provider-config","phabricator"],"backgroundTag":"credential-not-found","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}