Navigation
View as Markdown

Account sharing on web

Account sharing maps to the access event. In v2 you called Rupt.attach; in v3 you call rupt.evaluate.access from the same place, once per protected page view, for paying users. The call site does not move. What changes is the package, the way you create the client, and the shape of the call.

Step 1: Swap the package

# remove the v2 package
npm uninstall rupt

# add the v3 client
npm install @ruptjs/client

Then update the import:

// v2
import Rupt from "rupt";

// v3
import Rupt from "@ruptjs/client";

Step 2: Create a client, then evaluate

v2 was a single global call. v3 creates a client once (this is where the logout callback lives) and calls evaluate.access at the same spot attach used to run.

// v2
import Rupt from "rupt";

await Rupt.attach({
  client_id: "your_client_id",
  account: user.id,
  redirect_urls: {
    logout_url: "https://yourapp.com/logout",
    new_account_url: "https://yourapp.com/signup",
  },
  on_current_device_logout: () => {
    // Clear your session and sign the user out locally.
  },
  on_limit_exceeded: () => {},
  on_challenge: () => true,
});
// v3
import Rupt from "@ruptjs/client";

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

// Same call site as attach: once per protected page, for paying users.
await rupt.evaluate.access({
  user: user.id,
  email: user.email,
  phone: user.phone,
});

When Rupt detects sharing, the SDK redirects to the challenge on its own and brings the user back. You do not read the response for this. If you would rather intercept the challenge instead of auto-redirecting, pass auto_challenge: false and read response.redirect yourself.

Step 3: Recreate your policies

v2 shipped with default account-sharing behavior. In v3 that behavior is explicit: it lives in policies you create in your policies dashboard, on the access event. Recreate the three checks v2 came with, each triggering an account-sharing challenge:

  • Device limits (device_count): more devices than one person uses.
  • Impossible travel (impossible_travel): back-to-back activity from locations too far apart to bridge.
  • Concurrency (concurrent_sessions): the account is live in two places at once.

Start from these three, then tune to your preference. Until a policy exists on the access event, evaluate.access just gathers signals and never challenges anyone.

Step 4: Set the challenge URLs

In v2, redirect_urls lived in the attach call. In v3 they live on the policy's challenge config:

  • Success URL: where a blocked user goes to create their own account. Point it at your signup page. Someone who hits a sharing challenge is high intent, so this converts the extra user instead of turning them away.
  • Logout URL: where a device is redirected when it gets logged out. On the challenge screen, when the user chooses to log out the current device, that's where it lands.

The Logout URL is not the same as the on_logout callback, and account sharing uses both:

  • Logout URL is a redirect, for the device the user is logging out from on the challenge page.
  • on_logout is a callback that fires when the current session is logged out remotely, that is, when the user logs this device out from somewhere else. Use it to clear your app's own session. If a Logout URL is set, the SDK navigates there too; if not, on_logout is your only hook.

What went away

v2 (attach)v3
client_idclientId on the constructor
accountuser
redirect_urlsSuccess and Logout URLs on the policy's challenge config
on_current_device_logouton_logout on the constructor (or per call)
on_challengeRemoved. The challenge auto-redirects (auto_challenge defaults on for access)
on_limit_exceededRemoved. Cap devices with a device_count policy
limit_config, tolerance, cookie, secretRemoved from the call. Limits and tolerance are policy-side
device_id, attached_devices, access in the responseNot returned. You do not need them client-side