passbolt/passbolt_api · error · BadRequestException
The key provided does not belong to given user.
Error message
The key provided does not belong to given user.
What it means
Thrown by validateData in RecoverCompleteService when the fingerprint of the OpenPGP key submitted with the recovery does not match any stored key for that user. Recovery re-registers the user's ORIGINAL key, so a different key is rejected to prevent an attacker swapping keys.
Solutions
- Use the exact key pair originally registered for this account (fingerprint must match the stored gpgkeys.fingerprint)
- If the key is truly lost, an administrator must delete the user's account key / re-invite the user so a new key can be registered
- Compare fingerprints locally before calling: gpg --show-keys <file> and diff against the stored fingerprint
- Ensure only the primary key's armored block is sent, not a subkey-only export
Example fix
// before: recovering with a freshly generated key const armor = await generateAndExportNewKey(); await recoverComplete(userId, token, armor); // after: use the original registered key const armor = await exportOriginalRegisteredKey(); await recoverComplete(userId, token, armor);
Defensive patterns
Strategy: validation
Validate before calling
const fp = await getFingerprint(armoredKey);
const stored = await getStoredFingerprint(userId);
if (fp !== stored) throw new Error('key does not match account'); Try / catch
try { await recoverComplete(userId, token, armoredKey); }
catch (e) { if (isKeyMismatch(e)) { /* contact admin — original key required */ } else throw e; } Prevention
- Always use the originally registered key pair for recovery
- Compare fingerprints (gpg --show-keys) before submitting
- Never regenerate a key expecting recovery to accept it
- Export the primary key, not a subkey-only block
When it happens
Trigger: POST /setup/recover/complete/{userId}/{token} with gpgkey.armored_key whose fingerprint differs from the user's stored Gpgkeys row; user regenerated/lost their key and tries to recover with the new one.
Common situations: User lost their private key and generated a new pair hoping to recover; importing the wrong key file (another account's key); key with multiple subkeys where the wrong primary fingerprint is derived; typo when pasting the armored key.
Related errors
- Decryption failed. Invalid signature. Expected
- There is an issue with the OpenPGP server key. The…
- A valid OpenPGP key must be provided.
- A valid OpenPGP key must be provided.
- A value for the theme should be provided.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/57fdf7fe3dec1ea0.
Report an issue: GitHub.
Appendix: source
Thrown at src/Service/Setup/RecoverCompleteService.php:97
}
/**
* Validate the user and the gpgkey
*
* @param string $userId User ID
* @return \App\Model\Entity\User
* @throws \Cake\Http\Exception\BadRequestException if the data provided is not valid
*/
protected function validateData(string $userId): User
{
// Check request sanity
$user = $this->getAndAssertUser($userId);
$gpgkey = $this->getAndAssertGpgkey($userId);
// Check that the "new" gpg key match the old one
$userKey = $this->Gpgkeys->getByFingerprintAndUserId($gpgkey->fingerprint, $userId);
if (empty($userKey)) {
throw new BadRequestException(__('The key provided does not belong to given user.'));
}
return $user;
}
/**
* Return the user for matching the requesting id
*
* @param string $userId the user uuid
* @throws \Cake\Http\Exception\BadRequestException if the user id is not a valid uuid
* @throws \Cake\Http\Exception\BadRequestException if the user was deleted or has not completed the setup
* @return \App\Model\Entity\User
*/
protected function getAndAssertUser(string $userId): User
{
try {
return (new UserGetService())->getActiveNotDeletedNotDisabledOrFail($userId);
} catch (NotFoundException $exception) {View on GitHub (pinned to 31c1bbc10f)