Navigation
View as Markdown

Access protection

Access protection is how Rupt defends against account sharing: one subscription quietly used by several people.

Account sharing is a special case, and it's handled differently from login and signup.

  • It leans on devices, not fingerprints, and the goal is growth, not blocking. A shared account is a paying customer with extra people attached. The win is converting those extra people into their own accounts, not locking anyone out.
  • False positives are worse than false negatives. Users accept tight login security — you're protecting their credentials. But challenging someone for sharing when they aren't is infuriating. That's why Rupt errs on the side of caution.

Like the other fundamentals, this builds on the challenge flow, but it's fully self-managed. You call evaluate.access and Rupt handles detection, the challenge, owner verification, and device capping client-side. There's no server step and no evaluation to consume.

Step 1: Evaluate on access

Call evaluate.access once on every page view (do it only for paid content and paying users -- you don't care if free users are sharing). Pass user, and include email and/or phone so the verification challenge can reach the owner.

Set up the on_logout callback at the same time. The device-limit challenge can log a device out, and the callback is how your app clears its own session when that happens.

import Rupt from "@ruptjs/client";

const rupt = new Rupt({
  clientId: "your_client_id",
  on_logout: () => {
    // Clear your session and sign the user out locally.
  },
});

// Call this on every protected page.
await rupt.evaluate.access({
  user: user.id,
  email: user.email,
  phone: user.phone,
});

When Rupt detects sharing, the SDK redirects to the challenge, runs verification or the device cap, and brings the user back, all client-side. There's nothing to fetch or confirm on your server.

Step 2: Create the policy and its URLs

This is the last piece, and it's what turns detection on. Until a policy exists, evaluate.access just gathers signals and never challenges anyone.

In the dashboard, create a policy on the access event with action challenge. Gate it on the sharing checks:

  • concurrent_sessions: the account is live in two places at once.
  • impossible_travel: back-to-back activity from locations too far apart to bridge.
  • device_count, or the per-type computer_device_count / tablet_device_count / mobile_device_count: more devices than one person uses.

There are two kinds of account-sharing challenge:

  • Verification challenge — for concurrent_sessions and impossible_travel. Rupt asks the suspected owner to verify with an email or SMS code.
  • Device-limit challenge — for the device counts. Rupt asks the user to log devices out until the account is back under your limit.

A common setup is two policies: one that verifies on concurrency or impossible travel, and one that caps devices on count. Keep the thresholds generous — given the false-positive cost above, start loose and tighten only if you need to.

On the policy's challenge config, set two URLs:

  • Success URL — where a blocked user goes to create their own account (your signup page). Someone who hits a sharing challenge is high-intent, so this converts the extra user instead of turning them away. For high-value B2B, pointing them to book a meeting works just as well.
  • Logout URL — where the user lands when they're logged out of the shared account. This is the redirect that pairs with your on_logout callback; log your existing user out here first, so they can create their own account cleanly.