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

  1. Re-authenticate to obtain a fresh refresh token; the presented one no longer exists in an active state.
  2. Verify the token and userId belong together and are passed in the correct order.
  3. Check the user account exists and is active (users.deleted=false, not deactivated).
  4. 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

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


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)