passbolt/passbolt_api · error · RefreshTokenNotFoundException
No active refresh token matching the request could be found.
Error message
No active refresh token matching the request could be found.
What it means
getActiveRefreshToken throws RefreshTokenNotFoundException ('No active refresh token matching the request could be found') when the (token, userId) pair matches no active AuthenticationToken row, or when the associated user has since been deleted/deactivated. It is a 404-style signal that the presented credentials do not correspond to a live refresh session.
Solutions
- Re-authenticate to obtain a fresh refresh token; the presented one no longer exists in an active state.
- Verify the token and userId belong together and are passed in the correct order.
- Check the user account exists and is active (users.deleted=false, not deactivated).
- If logout, treat this as 'already logged out' and clear local credentials idempotently.
Example fix
// before
await logout(token, userId); // throws if token already revoked
// after
try { await logout(token, userId); } catch (RefreshTokenNotFound) { clearLocalSession(); } // idempotent logout Defensive patterns
Strategy: try-catch
Validate before calling
const userActive = !(user.deleted || user.disabled); if (!isUuid(token) || !isUuid(userId) || !userActive) skipLogoutCall();
Type guard
function isLiveSession(tok: string, uid: string, user: User): boolean {
return isUuid(tok) && isUuid(uid) && !user.deleted && !user.disabled;
} Try / catch
try {
$service->getActiveRefreshToken($token, $userId);
} catch (RefreshTokenNotFoundException $e) {
// already logged out / token revoked — clear local state, don't surface 500
$this->clearLocalSession();
} Prevention
- Treat 'token not found' on logout as an idempotent success
- Re-authenticate instead of retrying with the same token after revocation
- Verify user accounts are active before resuming refresh flows after admin actions
When it happens
Trigger: Logging out with a token that was already revoked or rotated; a user id that does not match the token's owner; the user account being deleted or deactivated after the token was issued; querying a database that was migrated/reset and no longer has the token row.
Common situations: Stale client credentials after a server database restore; revoked tokens following an admin deactivation; typo'd or swapped token/userId arguments; multi-server setups without shared database state.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- No active refresh token matching the request could be found.
- Expired refresh token provided.
- The user does not exist or has been deleted.
- Attempt to access an expired verify token.
- Could not import the user OpenPGP key.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/a83f2e5271c9382f.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltCe/JwtAuthentication/src/Service/RefreshToken/RefreshTokenAbstractService.php:187
->where([$this->AuthenticationTokens->aliasField('user_id') => $userId]);
}
/**
* @param string $token token to retrieve
* @param string $userId user ID
* @return \App\Model\Entity\AuthenticationToken Refresh token
* @throws \Passbolt\JwtAuthentication\Error\Exception\RefreshToken\RefreshTokenNotFoundException if the token is not found
* @throws \Passbolt\JwtAuthentication\Error\Exception\RefreshToken\ConsumedRefreshTokenAccessException if the token was already consumed
* @throws \Passbolt\JwtAuthentication\Error\Exception\RefreshToken\ExpiredRefreshTokenAccessException if the token is expired
* @throws \InvalidArgumentException If the given token or user identifier are not a valid UUIDs
*/
public function getActiveRefreshToken(string $token, string $userId): AuthenticationToken
{
/** @var \App\Model\Entity\AuthenticationToken|null $refreshToken */
$refreshToken = $this->queryRefreshTokenWithUserId($token, $userId)->contain('Users')->first();
if ($refreshToken === null) {
throw new RefreshTokenNotFoundException();
}
// Check if the user was not deleted or deactivated since the refresh token was issued.
$user = $refreshToken->user;
if ($user->isDeleted()) {
throw new UserDeletedException();
} elseif (!$user->isActive()) {
throw new UserDeactivatedException();
} elseif ($user->isDisabled()) {
throw new UserDeactivatedException();
}
$this->throwSecurityExceptionsOnInvalidRefreshToken($refreshToken);
return $refreshToken;
}
/**View on GitHub (pinned to 31c1bbc10f)