---
title: Access protection
---

# Access protection

Access protection is how Rupt defends against [account sharing](/docs/v3/concepts/account-sharing): one subscription quietly used by several people.

::alert{type="warning"}
Account sharing is a special case, and it's handled differently from login and signup.

- **It leans on [devices](/docs/v3/concepts/devices), not [fingerprints](/docs/v3/concepts/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](/docs/v3/fundamentals), this builds on the [challenge flow](/docs/v3/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.

::ClientPlatform

#web

```js
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,
});
```

#ios

```swift
// Set on_logout when you create the client, then call evaluate on every screen.
try await rupt.evaluate(
  action: "access",
  user: user.id,
  email: user.email,
  phone: user.phone
)
```

#android

```kotlin
// Set on_logout when you create the client, then call evaluate on every screen.
rupt.evaluate(
  action = "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](/docs/v3/concepts/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.

## Related

- [Account sharing](/docs/v3/concepts/account-sharing): the risk and the checks behind it.
- [Account sharing prevention](/docs/v3/guides/account-sharing-prevention): the same pattern in the guides section.
- [Concurrency](/docs/v3/concepts/concurrency) and [Devices](/docs/v3/concepts/devices): what the policy matches on.
