[{"data":1,"prerenderedAt":835},["ShallowReactive",2],{"docsv3-nav":3,"\u002Fdocs\u002Fv3\u002Ffundamentals\u002Faccess-protection":198},[4],{"title":5,"path":6,"stem":7,"children":8,"page":188},"V3","\u002Fdocs\u002Fv3","1.docs\u002Fv3",[9,13,17,21,38,87,189],{"title":10,"path":11,"stem":12},"Introduction","\u002Fdocs\u002Fv3\u002Fintroduction","1.docs\u002Fv3\u002F1.Introduction",{"title":14,"path":15,"stem":16},"Quick start","\u002Fdocs\u002Fv3\u002Fquick-start","1.docs\u002Fv3\u002F2.Quick start",{"title":18,"path":19,"stem":20},"Challenge flow","\u002Fdocs\u002Fv3\u002Fchallenge-flow","1.docs\u002Fv3\u002F3.Challenge flow",{"title":22,"path":23,"stem":24,"children":25},"Fundamentals","\u002Fdocs\u002Fv3\u002Ffundamentals","1.docs\u002Fv3\u002F4.fundamentals",[26,30,34],{"title":27,"path":28,"stem":29},"Signup protection","\u002Fdocs\u002Fv3\u002Ffundamentals\u002Fsignup-protection","1.docs\u002Fv3\u002F4.fundamentals\u002F00.Signup protection",{"title":31,"path":32,"stem":33},"Login protection","\u002Fdocs\u002Fv3\u002Ffundamentals\u002Flogin-protection","1.docs\u002Fv3\u002F4.fundamentals\u002F01.Login protection",{"title":35,"path":36,"stem":37},"Access protection","\u002Fdocs\u002Fv3\u002Ffundamentals\u002Faccess-protection","1.docs\u002Fv3\u002F4.fundamentals\u002F02.Access protection",{"title":39,"path":40,"stem":41,"children":42},"Guides","\u002Fdocs\u002Fv3\u002Fguides","1.docs\u002Fv3\u002F5.guides",[43,47,51,55,59,63,67,71,75,79,83],{"title":44,"path":45,"stem":46},"Account sharing prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Faccount-sharing-prevention","1.docs\u002Fv3\u002F5.guides\u002F1.Account sharing prevention",{"title":48,"path":49,"stem":50},"Web scraping prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Fweb-scraping-prevention","1.docs\u002Fv3\u002F5.guides\u002F13.Web scraping prevention",{"title":52,"path":53,"stem":54},"Ban enforcement","\u002Fdocs\u002Fv3\u002Fguides\u002Fban-enforcement","1.docs\u002Fv3\u002F5.guides\u002F14.Ban enforcement",{"title":56,"path":57,"stem":58},"Chargeback dispute","\u002Fdocs\u002Fv3\u002Fguides\u002Fchargeback-dispute","1.docs\u002Fv3\u002F5.guides\u002F15.Chargeback dispute",{"title":60,"path":61,"stem":62},"Multi-accounting prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Fmulti-accounting-prevention","1.docs\u002Fv3\u002F5.guides\u002F16.Multi-accounting prevention",{"title":64,"path":65,"stem":66},"Account takeover prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Faccount-takeover-prevention","1.docs\u002Fv3\u002F5.guides\u002F2.Account takeover prevention",{"title":68,"path":69,"stem":70},"Risky transaction prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Frisky-transaction-prevention","1.docs\u002Fv3\u002F5.guides\u002F20.Risky transaction prevention",{"title":72,"path":73,"stem":74},"Fake account detection","\u002Fdocs\u002Fv3\u002Fguides\u002Ffake-account-detection","1.docs\u002Fv3\u002F5.guides\u002F3.Fake account detection",{"title":76,"path":77,"stem":78},"Bot detection","\u002Fdocs\u002Fv3\u002Fguides\u002Fbot-detection","1.docs\u002Fv3\u002F5.guides\u002F4.Bot detection",{"title":80,"path":81,"stem":82},"Card testing prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Fcard-testing-prevention","1.docs\u002Fv3\u002F5.guides\u002F5.Card testing prevention",{"title":84,"path":85,"stem":86},"Incentive abuse prevention","\u002Fdocs\u002Fv3\u002Fguides\u002Fincentive-abuse-prevention","1.docs\u002Fv3\u002F5.guides\u002F9.Incentive abuse prevention",{"title":88,"path":89,"stem":90,"children":91,"page":188},"Concepts","\u002Fdocs\u002Fv3\u002Fconcepts","1.docs\u002Fv3\u002F6.concepts",[92,96,100,104,108,112,116,120,124,128,132,136,140,144,148,152,156,160,164,168,172,176,180,184],{"title":93,"path":94,"stem":95},"Evaluations","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fevaluations","1.docs\u002Fv3\u002F6.concepts\u002F01.evaluations",{"title":97,"path":98,"stem":99},"Actions","\u002Fdocs\u002Fv3\u002Fconcepts\u002Factions","1.docs\u002Fv3\u002F6.concepts\u002F02.actions",{"title":101,"path":102,"stem":103},"Signals","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fsignals","1.docs\u002Fv3\u002F6.concepts\u002F03.signals",{"title":105,"path":106,"stem":107},"Checks","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fchecks","1.docs\u002Fv3\u002F6.concepts\u002F04.checks",{"title":109,"path":110,"stem":111},"Risks","\u002Fdocs\u002Fv3\u002Fconcepts\u002Frisks","1.docs\u002Fv3\u002F6.concepts\u002F05.risks",{"title":113,"path":114,"stem":115},"Verdicts","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fverdicts","1.docs\u002Fv3\u002F6.concepts\u002F06.verdicts",{"title":117,"path":118,"stem":119},"Policies","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fpolicies","1.docs\u002Fv3\u002F6.concepts\u002F07.policies",{"title":121,"path":122,"stem":123},"Challenges","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fchallenges","1.docs\u002Fv3\u002F6.concepts\u002F08.challenges",{"title":125,"path":126,"stem":127},"Concurrency","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fconcurrency","1.docs\u002Fv3\u002F6.concepts\u002F09.concurrency",{"title":129,"path":130,"stem":131},"Impossible travel","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fimpossible-travel","1.docs\u002Fv3\u002F6.concepts\u002F10.impossible-travel",{"title":133,"path":134,"stem":135},"Bots","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fbots","1.docs\u002Fv3\u002F6.concepts\u002F11.bots",{"title":137,"path":138,"stem":139},"Devices","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fdevices","1.docs\u002Fv3\u002F6.concepts\u002F12.devices",{"title":141,"path":142,"stem":143},"Fingerprints","\u002Fdocs\u002Fv3\u002Fconcepts\u002Ffingerprints","1.docs\u002Fv3\u002F6.concepts\u002F13.fingerprints",{"title":145,"path":146,"stem":147},"People","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fpeople","1.docs\u002Fv3\u002F6.concepts\u002F14.people",{"title":149,"path":150,"stem":151},"Lists","\u002Fdocs\u002Fv3\u002Fconcepts\u002Flists","1.docs\u002Fv3\u002F6.concepts\u002F15.lists",{"title":153,"path":154,"stem":155},"Account takeover","\u002Fdocs\u002Fv3\u002Fconcepts\u002Faccount-takeover","1.docs\u002Fv3\u002F6.concepts\u002F16.account-takeover",{"title":157,"path":158,"stem":159},"Account sharing","\u002Fdocs\u002Fv3\u002Fconcepts\u002Faccount-sharing","1.docs\u002Fv3\u002F6.concepts\u002F17.account-sharing",{"title":161,"path":162,"stem":163},"Fake account","\u002Fdocs\u002Fv3\u002Fconcepts\u002Ffake-account","1.docs\u002Fv3\u002F6.concepts\u002F18.fake-account",{"title":165,"path":166,"stem":167},"Scraping","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fscraping","1.docs\u002Fv3\u002F6.concepts\u002F19.scraping",{"title":169,"path":170,"stem":171},"Linked accounts","\u002Fdocs\u002Fv3\u002Fconcepts\u002Flinked-accounts","1.docs\u002Fv3\u002F6.concepts\u002F20.linked-accounts",{"title":173,"path":174,"stem":175},"New IP","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fip","1.docs\u002Fv3\u002F6.concepts\u002F21.ip",{"title":177,"path":178,"stem":179},"Anonymizing network","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fanonymizing-network","1.docs\u002Fv3\u002F6.concepts\u002F22.anonymizing-network",{"title":181,"path":182,"stem":183},"Email quality","\u002Fdocs\u002Fv3\u002Fconcepts\u002Femail","1.docs\u002Fv3\u002F6.concepts\u002F23.email",{"title":185,"path":186,"stem":187},"Velocity","\u002Fdocs\u002Fv3\u002Fconcepts\u002Fvelocity","1.docs\u002Fv3\u002F6.concepts\u002F24.velocity",false,{"title":190,"path":191,"stem":192,"children":193,"page":188},"Advanced","\u002Fdocs\u002Fv3\u002Fadvanced","1.docs\u002Fv3\u002F7.Advanced",[194],{"title":195,"path":196,"stem":197},"Proxy setup","\u002Fdocs\u002Fv3\u002Fadvanced\u002Fproxy-setup","1.docs\u002Fv3\u002F7.Advanced\u002F1.Proxy-setup",{"id":199,"title":35,"body":200,"description":829,"extension":830,"meta":831,"navigation":345,"path":36,"rawbody":832,"seo":833,"stem":37,"__hash__":834},"docsv3\u002F1.docs\u002Fv3\u002F4.fundamentals\u002F02.Access protection.md",{"type":201,"value":202,"toc":824},"minimark",[203,207,216,248,264,269,287,294,686,689,693,699,712,743,746,766,769,772,797,801,820],[204,205,35],"h1",{"id":206},"access-protection",[208,209,210,211,215],"p",{},"Access protection is how Rupt defends against ",[212,213,214],"a",{"href":158},"account sharing",": one subscription quietly used by several people.",[217,218,220,223],"alert",{"type":219},"warning",[208,221,222],{},"Account sharing is a special case, and it's handled differently from login and signup.",[224,225,226,242],"ul",{},[227,228,229,241],"li",{},[230,231,232,233,236,237,240],"strong",{},"It leans on ",[212,234,235],{"href":138},"devices",", not ",[212,238,239],{"href":142},"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.",[227,243,244,247],{},[230,245,246],{},"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.",[208,249,250,251,254,255,258,259,263],{},"Like the other ",[212,252,253],{"href":23},"fundamentals",", this builds on the ",[212,256,257],{"href":19},"challenge flow",", but it's fully self-managed. You call ",[260,261,262],"code",{},"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.",[265,266,268],"h2",{"id":267},"step-1-evaluate-on-access","Step 1: Evaluate on access",[208,270,271,272,274,275,278,279,282,283,286],{},"Call ",[260,273,262],{}," once on every page view (do it only for paid content and paying users -- you don't care if free users are sharing). Pass ",[260,276,277],{},"user",", and include ",[260,280,281],{},"email"," and\u002For ",[260,284,285],{},"phone"," so the verification challenge can reach the owner.",[208,288,289,290,293],{},"Set up the ",[260,291,292],{},"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.",[295,296,297,530,617],"client-platform",{},[298,299,301],"template",{"v-slot:web":300},"",[302,303,307],"pre",{"className":304,"code":305,"language":306,"meta":300,"style":300},"language-js shiki shiki-themes material-theme-lighter one-dark-pro monokai","import Rupt from \"@ruptjs\u002Fclient\";\n\nconst rupt = new Rupt({\n  clientId: \"your_client_id\",\n  on_logout: () => {\n    \u002F\u002F Clear your session and sign the user out locally.\n  },\n});\n\n\u002F\u002F Call this on every protected page.\nawait rupt.evaluate.access({\n  user: user.id,\n  email: user.email,\n  phone: user.phone,\n});\n","js",[260,308,309,340,347,376,396,413,420,426,437,442,448,471,489,505,521],{"__ignoreMap":300},[310,311,314,318,322,325,329,333,336],"span",{"class":312,"line":313},"line",1,[310,315,317],{"class":316},"sAPXc","import",[310,319,321],{"class":320},"seeE2"," Rupt",[310,323,324],{"class":316}," from",[310,326,328],{"class":327},"s9QZx"," \"",[310,330,332],{"class":331},"siibJ","@ruptjs\u002Fclient",[310,334,335],{"class":327},"\"",[310,337,339],{"class":338},"shEKG",";\n",[310,341,343],{"class":312,"line":342},2,[310,344,346],{"emptyLinePlaceholder":345},true,"\n",[310,348,350,354,358,362,366,369,373],{"class":312,"line":349},3,[310,351,353],{"class":352},"sHm3x","const",[310,355,357],{"class":356},"sZ9uN"," rupt",[310,359,361],{"class":360},"sut_7"," =",[310,363,365],{"class":364},"srTuz"," new",[310,367,321],{"class":368},"sjp9t",[310,370,372],{"class":371},"sJCYa","(",[310,374,375],{"class":338},"{\n",[310,377,379,383,386,388,391,393],{"class":312,"line":378},4,[310,380,382],{"class":381},"sUwfj","  clientId",[310,384,385],{"class":338},":",[310,387,328],{"class":327},[310,389,390],{"class":331},"your_client_id",[310,392,335],{"class":327},[310,394,395],{"class":338},",\n",[310,397,399,402,404,407,410],{"class":312,"line":398},5,[310,400,401],{"class":368},"  on_logout",[310,403,385],{"class":338},[310,405,406],{"class":338}," ()",[310,408,409],{"class":352}," =>",[310,411,412],{"class":338}," {\n",[310,414,416],{"class":312,"line":415},6,[310,417,419],{"class":418},"s42Qa","    \u002F\u002F Clear your session and sign the user out locally.\n",[310,421,423],{"class":312,"line":422},7,[310,424,425],{"class":338},"  },\n",[310,427,429,432,435],{"class":312,"line":428},8,[310,430,431],{"class":338},"}",[310,433,434],{"class":371},")",[310,436,339],{"class":338},[310,438,440],{"class":312,"line":439},9,[310,441,346],{"emptyLinePlaceholder":345},[310,443,445],{"class":312,"line":444},10,[310,446,447],{"class":418},"\u002F\u002F Call this on every protected page.\n",[310,449,451,454,456,459,462,464,467,469],{"class":312,"line":450},11,[310,452,453],{"class":316},"await",[310,455,357],{"class":356},[310,457,458],{"class":338},".",[310,460,461],{"class":356},"evaluate",[310,463,458],{"class":338},[310,465,466],{"class":368},"access",[310,468,372],{"class":371},[310,470,375],{"class":338},[310,472,474,477,479,482,484,487],{"class":312,"line":473},12,[310,475,476],{"class":381},"  user",[310,478,385],{"class":338},[310,480,481],{"class":356}," user",[310,483,458],{"class":338},[310,485,486],{"class":320},"id",[310,488,395],{"class":338},[310,490,492,495,497,499,501,503],{"class":312,"line":491},13,[310,493,494],{"class":381},"  email",[310,496,385],{"class":338},[310,498,481],{"class":356},[310,500,458],{"class":338},[310,502,281],{"class":320},[310,504,395],{"class":338},[310,506,508,511,513,515,517,519],{"class":312,"line":507},14,[310,509,510],{"class":381},"  phone",[310,512,385],{"class":338},[310,514,481],{"class":356},[310,516,458],{"class":338},[310,518,285],{"class":320},[310,520,395],{"class":338},[310,522,524,526,528],{"class":312,"line":523},15,[310,525,431],{"class":338},[310,527,434],{"class":371},[310,529,339],{"class":338},[298,531,532],{"v-slot:ios":300},[302,533,537],{"className":534,"code":535,"language":536,"meta":300,"style":300},"language-swift shiki shiki-themes material-theme-lighter one-dark-pro monokai","\u002F\u002F Set on_logout when you create the client, then call evaluate on every screen.\ntry await rupt.evaluate(\n  action: \"access\",\n  user: user.id,\n  email: user.email,\n  phone: user.phone\n)\n","swift",[260,538,539,544,561,576,589,601,612],{"__ignoreMap":300},[310,540,541],{"class":312,"line":313},[310,542,543],{"class":418},"\u002F\u002F Set on_logout when you create the client, then call evaluate on every screen.\n",[310,545,546,549,552,555,558],{"class":312,"line":342},[310,547,548],{"class":316},"try",[310,550,551],{"class":316}," await",[310,553,554],{"class":371}," rupt.",[310,556,461],{"class":557},"sh6BQ",[310,559,560],{"class":338},"(\n",[310,562,563,566,568,570,572,574],{"class":312,"line":349},[310,564,565],{"class":557},"  action",[310,567,385],{"class":338},[310,569,328],{"class":327},[310,571,466],{"class":331},[310,573,335],{"class":327},[310,575,395],{"class":371},[310,577,578,580,582,585,587],{"class":312,"line":378},[310,579,476],{"class":557},[310,581,385],{"class":338},[310,583,584],{"class":371}," user.",[310,586,486],{"class":320},[310,588,395],{"class":371},[310,590,591,593,595,597,599],{"class":312,"line":398},[310,592,494],{"class":557},[310,594,385],{"class":338},[310,596,584],{"class":371},[310,598,281],{"class":320},[310,600,395],{"class":371},[310,602,603,605,607,609],{"class":312,"line":415},[310,604,510],{"class":557},[310,606,385],{"class":338},[310,608,584],{"class":371},[310,610,611],{"class":320},"phone\n",[310,613,614],{"class":312,"line":422},[310,615,616],{"class":338},")\n",[298,618,619],{"v-slot:android":300},[302,620,624],{"className":621,"code":622,"language":623,"meta":300,"style":300},"language-kotlin shiki shiki-themes material-theme-lighter one-dark-pro monokai","\u002F\u002F Set on_logout when you create the client, then call evaluate on every screen.\nrupt.evaluate(\n  action = \"access\",\n  user = user.id,\n  email = user.email,\n  phone = user.phone,\n)\n","kotlin",[260,625,626,630,639,652,662,672,682],{"__ignoreMap":300},[310,627,628],{"class":312,"line":313},[310,629,543],{"class":418},[310,631,632,635,637],{"class":312,"line":342},[310,633,634],{"class":371},"rupt.",[310,636,461],{"class":368},[310,638,560],{"class":371},[310,640,641,644,647,650],{"class":312,"line":349},[310,642,643],{"class":371},"  action ",[310,645,646],{"class":360},"=",[310,648,649],{"class":331}," \"access\"",[310,651,395],{"class":371},[310,653,654,657,659],{"class":312,"line":378},[310,655,656],{"class":371},"  user ",[310,658,646],{"class":360},[310,660,661],{"class":371}," user.id,\n",[310,663,664,667,669],{"class":312,"line":398},[310,665,666],{"class":371},"  email ",[310,668,646],{"class":360},[310,670,671],{"class":371}," user.email,\n",[310,673,674,677,679],{"class":312,"line":415},[310,675,676],{"class":371},"  phone ",[310,678,646],{"class":360},[310,680,681],{"class":371}," user.phone,\n",[310,683,684],{"class":312,"line":422},[310,685,616],{"class":371},[208,687,688],{},"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.",[265,690,692],{"id":691},"step-2-create-the-policy-and-its-urls","Step 2: Create the policy and its URLs",[208,694,695,696,698],{},"This is the last piece, and it's what turns detection on. Until a policy exists, ",[260,697,262],{}," just gathers signals and never challenges anyone.",[208,700,701,702,704,705,708,709,385],{},"In the dashboard, create a policy on the ",[230,703,466],{}," event with action ",[230,706,707],{},"challenge",". Gate it on the sharing ",[212,710,711],{"href":106},"checks",[224,713,714,720,726],{},[227,715,716,719],{},[260,717,718],{},"concurrent_sessions",": the account is live in two places at once.",[227,721,722,725],{},[260,723,724],{},"impossible_travel",": back-to-back activity from locations too far apart to bridge.",[227,727,728,731,732,735,736,735,739,742],{},[260,729,730],{},"device_count",", or the per-type ",[260,733,734],{},"computer_device_count"," \u002F ",[260,737,738],{},"tablet_device_count",[260,740,741],{},"mobile_device_count",": more devices than one person uses.",[208,744,745],{},"There are two kinds of account-sharing challenge:",[224,747,748,760],{},[227,749,750,753,754,756,757,759],{},[230,751,752],{},"Verification challenge"," — for ",[260,755,718],{}," and ",[260,758,724],{},". Rupt asks the suspected owner to verify with an email or SMS code.",[227,761,762,765],{},[230,763,764],{},"Device-limit challenge"," — for the device counts. Rupt asks the user to log devices out until the account is back under your limit.",[208,767,768],{},"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.",[208,770,771],{},"On the policy's challenge config, set two URLs:",[224,773,774,788],{},[227,775,776,779,780,783,784,787],{},[230,777,778],{},"Success URL"," — where a blocked user goes to ",[230,781,782],{},"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 ",[230,785,786],{},"book a meeting"," works just as well.",[227,789,790,793,794,796],{},[230,791,792],{},"Logout URL"," — where the user lands when they're logged out of the shared account. This is the redirect that pairs with your ",[260,795,292],{}," callback; log your existing user out here first, so they can create their own account cleanly.",[265,798,800],{"id":799},"related","Related",[224,802,803,808,813],{},[227,804,805,807],{},[212,806,157],{"href":158},": the risk and the checks behind it.",[227,809,810,812],{},[212,811,44],{"href":45},": the same pattern in the guides section.",[227,814,815,756,817,819],{},[212,816,125],{"href":126},[212,818,137],{"href":138},": what the policy matches on.",[821,822,823],"style",{},"html pre.shiki code .sAPXc, html code.shiki .sAPXc{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#F92672;--shiki-dark-font-style:inherit}html pre.shiki code .seeE2, html code.shiki .seeE2{--shiki-light:#90A4AE;--shiki-default:#E06C75;--shiki-dark:#F8F8F2}html pre.shiki code .s9QZx, html code.shiki .s9QZx{--shiki-light:#39ADB5;--shiki-default:#98C379;--shiki-dark:#E6DB74}html pre.shiki code .siibJ, html code.shiki .siibJ{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#E6DB74}html pre.shiki code .shEKG, html code.shiki .shEKG{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F8F8F2}html pre.shiki code .sHm3x, html code.shiki .sHm3x{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#C678DD;--shiki-default-font-style:inherit;--shiki-dark:#66D9EF;--shiki-dark-font-style:italic}html pre.shiki code .sZ9uN, html code.shiki .sZ9uN{--shiki-light:#90A4AE;--shiki-default:#E5C07B;--shiki-dark:#F8F8F2}html pre.shiki code .sut_7, html code.shiki .sut_7{--shiki-light:#39ADB5;--shiki-default:#56B6C2;--shiki-dark:#F92672}html pre.shiki code .srTuz, html code.shiki .srTuz{--shiki-light:#39ADB5;--shiki-default:#C678DD;--shiki-dark:#F92672}html pre.shiki code .sjp9t, html code.shiki .sjp9t{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#A6E22E}html pre.shiki code .sJCYa, html code.shiki .sJCYa{--shiki-light:#90A4AE;--shiki-default:#ABB2BF;--shiki-dark:#F8F8F2}html pre.shiki code .sUwfj, html code.shiki .sUwfj{--shiki-light:#E53935;--shiki-default:#E06C75;--shiki-dark:#F8F8F2}html pre.shiki code .s42Qa, html code.shiki .s42Qa{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#7F848E;--shiki-default-font-style:italic;--shiki-dark:#88846F;--shiki-dark-font-style:inherit}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sh6BQ, html code.shiki .sh6BQ{--shiki-light:#6182B8;--shiki-default:#61AFEF;--shiki-dark:#66D9EF}",{"title":300,"searchDepth":342,"depth":342,"links":825},[826,827,828],{"id":267,"depth":342,"text":268},{"id":691,"depth":342,"text":692},{"id":799,"depth":342,"text":800},"Access protection is how Rupt defends against account sharing: one subscription quietly used by several people.","md",{},"---\ntitle: Access protection\n---\n\n# Access protection\n\nAccess protection is how Rupt defends against [account sharing](\u002Fdocs\u002Fv3\u002Fconcepts\u002Faccount-sharing): one subscription quietly used by several people.\n\n::alert{type=\"warning\"}\nAccount sharing is a special case, and it's handled differently from login and signup.\n\n- **It leans on [devices](\u002Fdocs\u002Fv3\u002Fconcepts\u002Fdevices), not [fingerprints](\u002Fdocs\u002Fv3\u002Fconcepts\u002Ffingerprints), 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.\n- **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.\n\n::\n\nLike the other [fundamentals](\u002Fdocs\u002Fv3\u002Ffundamentals), this builds on the [challenge flow](\u002Fdocs\u002Fv3\u002Fchallenge-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.\n\n## Step 1: Evaluate on access\n\nCall `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\u002For `phone` so the verification challenge can reach the owner.\n\nSet 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.\n\n::ClientPlatform\n\n#web\n\n```js\nimport Rupt from \"@ruptjs\u002Fclient\";\n\nconst rupt = new Rupt({\n  clientId: \"your_client_id\",\n  on_logout: () => {\n    \u002F\u002F Clear your session and sign the user out locally.\n  },\n});\n\n\u002F\u002F Call this on every protected page.\nawait rupt.evaluate.access({\n  user: user.id,\n  email: user.email,\n  phone: user.phone,\n});\n```\n\n#ios\n\n```swift\n\u002F\u002F Set on_logout when you create the client, then call evaluate on every screen.\ntry await rupt.evaluate(\n  action: \"access\",\n  user: user.id,\n  email: user.email,\n  phone: user.phone\n)\n```\n\n#android\n\n```kotlin\n\u002F\u002F Set on_logout when you create the client, then call evaluate on every screen.\nrupt.evaluate(\n  action = \"access\",\n  user = user.id,\n  email = user.email,\n  phone = user.phone,\n)\n```\n\n::\n\nWhen 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.\n\n## Step 2: Create the policy and its URLs\n\nThis is the last piece, and it's what turns detection on. Until a policy exists, `evaluate.access` just gathers signals and never challenges anyone.\n\nIn the dashboard, create a policy on the **access** event with action **challenge**. Gate it on the sharing [checks](\u002Fdocs\u002Fv3\u002Fconcepts\u002Fchecks):\n\n- `concurrent_sessions`: the account is live in two places at once.\n- `impossible_travel`: back-to-back activity from locations too far apart to bridge.\n- `device_count`, or the per-type `computer_device_count` \u002F `tablet_device_count` \u002F `mobile_device_count`: more devices than one person uses.\n\nThere are two kinds of account-sharing challenge:\n\n- **Verification challenge** — for `concurrent_sessions` and `impossible_travel`. Rupt asks the suspected owner to verify with an email or SMS code.\n- **Device-limit challenge** — for the device counts. Rupt asks the user to log devices out until the account is back under your limit.\n\nA 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.\n\nOn the policy's challenge config, set two URLs:\n\n- **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.\n- **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.\n\n## Related\n\n- [Account sharing](\u002Fdocs\u002Fv3\u002Fconcepts\u002Faccount-sharing): the risk and the checks behind it.\n- [Account sharing prevention](\u002Fdocs\u002Fv3\u002Fguides\u002Faccount-sharing-prevention): the same pattern in the guides section.\n- [Concurrency](\u002Fdocs\u002Fv3\u002Fconcepts\u002Fconcurrency) and [Devices](\u002Fdocs\u002Fv3\u002Fconcepts\u002Fdevices): what the policy matches on.\n",{"title":35,"description":829},"0AT_p1unPSUsGyLW8rNcLpsPWAfmJuGAClAn4euHm30",1780344892897]