[{"data":1,"prerenderedAt":1085},["ShallowReactive",2],{"docsv3-nav":3,"\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-web":236},[4],{"title":5,"path":6,"stem":7,"children":8,"page":188},"V3","\u002Fdocs\u002Fv3","1.docs\u002Fv3",[9,13,17,21,38,87,189,198,219],{"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",{"title":199,"path":200,"stem":201,"children":202},"Integrations","\u002Fdocs\u002Fv3\u002Fintegrations","1.docs\u002Fv3\u002F8.integrations",[203,207,211,215],{"title":204,"path":205,"stem":206},"Kajabi","\u002Fdocs\u002Fv3\u002Fintegrations\u002Fkajabi-account-sharing-prevention","1.docs\u002Fv3\u002F8.integrations\u002F1.Kajabi account sharing prevention",{"title":208,"path":209,"stem":210},"Teachable","\u002Fdocs\u002Fv3\u002Fintegrations\u002Fteachable-account-sharing-prevention","1.docs\u002Fv3\u002F8.integrations\u002F2.Teachable account sharing prevention",{"title":212,"path":213,"stem":214},"Thinkific","\u002Fdocs\u002Fv3\u002Fintegrations\u002Fthinkific-account-sharing-prevention","1.docs\u002Fv3\u002F8.integrations\u002F3.Thinkific account sharing prevention",{"title":216,"path":217,"stem":218},"LearnWorlds","\u002Fdocs\u002Fv3\u002Fintegrations\u002Flearnworlds-account-sharing-prevention","1.docs\u002Fv3\u002F8.integrations\u002F4.LearnWorlds account sharing prevention",{"title":220,"path":221,"stem":222,"children":223,"page":188},"Migration","\u002Fdocs\u002Fv3\u002Fmigration","1.docs\u002Fv3\u002F9.migration",[224,228,232],{"title":225,"path":226,"stem":227},"Overview","\u002Fdocs\u002Fv3\u002Fmigration\u002Foverview","1.docs\u002Fv3\u002F9.migration\u002F1.Overview",{"title":229,"path":230,"stem":231},"Account sharing on web","\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-web","1.docs\u002Fv3\u002F9.migration\u002F2.Account sharing on web",{"title":233,"path":234,"stem":235},"Account sharing on mobile","\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-mobile","1.docs\u002Fv3\u002F9.migration\u002F3.Account sharing on mobile",{"id":237,"title":229,"body":238,"description":1079,"extension":1080,"meta":1081,"navigation":300,"path":230,"rawbody":1082,"seo":1083,"stem":231,"__hash__":1084},"docsv3\u002F1.docs\u002Fv3\u002F9.migration\u002F2.Account sharing on web.md",{"type":239,"value":240,"toc":1071},"minimark",[241,245,258,263,319,322,387,391,402,612,791,802,806,821,852,858,862,872,886,893,910,914,1045,1049,1067],[242,243,229],"h1",{"id":244},"account-sharing-on-web",[246,247,248,249,253,254,257],"p",{},"Account sharing maps to the access event. In v2 you called ",[250,251,252],"code",{},"Rupt.attach","; in v3 you call ",[250,255,256],{},"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.",[259,260,262],"h2",{"id":261},"step-1-swap-the-package","Step 1: Swap the package",[264,265,270],"pre",{"className":266,"code":267,"language":268,"meta":269,"style":269},"language-sh shiki shiki-themes material-theme-lighter one-dark-pro monokai","# remove the v2 package\nnpm uninstall rupt\n\n# add the v3 client\nnpm install @ruptjs\u002Fclient\n","sh","",[250,271,272,281,295,302,308],{"__ignoreMap":269},[273,274,277],"span",{"class":275,"line":276},"line",1,[273,278,280],{"class":279},"s42Qa","# remove the v2 package\n",[273,282,284,288,292],{"class":275,"line":283},2,[273,285,287],{"class":286},"sHrIR","npm",[273,289,291],{"class":290},"siibJ"," uninstall",[273,293,294],{"class":290}," rupt\n",[273,296,298],{"class":275,"line":297},3,[273,299,301],{"emptyLinePlaceholder":300},true,"\n",[273,303,305],{"class":275,"line":304},4,[273,306,307],{"class":279},"# add the v3 client\n",[273,309,311,313,316],{"class":275,"line":310},5,[273,312,287],{"class":286},[273,314,315],{"class":290}," install",[273,317,318],{"class":290}," @ruptjs\u002Fclient\n",[246,320,321],{},"Then update the import:",[264,323,327],{"className":324,"code":325,"language":326,"meta":269,"style":269},"language-js shiki shiki-themes material-theme-lighter one-dark-pro monokai","\u002F\u002F v2\nimport Rupt from \"rupt\";\n\n\u002F\u002F v3\nimport Rupt from \"@ruptjs\u002Fclient\";\n","js",[250,328,329,334,361,365,370],{"__ignoreMap":269},[273,330,331],{"class":275,"line":276},[273,332,333],{"class":279},"\u002F\u002F v2\n",[273,335,336,340,344,347,351,354,357],{"class":275,"line":283},[273,337,339],{"class":338},"sAPXc","import",[273,341,343],{"class":342},"seeE2"," Rupt",[273,345,346],{"class":338}," from",[273,348,350],{"class":349},"s9QZx"," \"",[273,352,353],{"class":290},"rupt",[273,355,356],{"class":349},"\"",[273,358,360],{"class":359},"shEKG",";\n",[273,362,363],{"class":275,"line":297},[273,364,301],{"emptyLinePlaceholder":300},[273,366,367],{"class":275,"line":304},[273,368,369],{"class":279},"\u002F\u002F v3\n",[273,371,372,374,376,378,380,383,385],{"class":275,"line":310},[273,373,339],{"class":338},[273,375,343],{"class":342},[273,377,346],{"class":338},[273,379,350],{"class":349},[273,381,382],{"class":290},"@ruptjs\u002Fclient",[273,384,356],{"class":349},[273,386,360],{"class":359},[259,388,390],{"id":389},"step-2-create-a-client-then-evaluate","Step 2: Create a client, then evaluate",[246,392,393,394,397,398,401],{},"v2 was a single global call. v3 creates a client once (this is where the logout callback lives) and calls ",[250,395,396],{},"evaluate.access"," at the same spot ",[250,399,400],{},"attach"," used to run.",[264,403,405],{"className":324,"code":404,"language":326,"meta":269,"style":269},"\u002F\u002F v2\nimport Rupt from \"rupt\";\n\nawait Rupt.attach({\n  client_id: \"your_client_id\",\n  account: user.id,\n  redirect_urls: {\n    logout_url: \"https:\u002F\u002Fyourapp.com\u002Flogout\",\n    new_account_url: \"https:\u002F\u002Fyourapp.com\u002Fsignup\",\n  },\n  on_current_device_logout: () => {\n    \u002F\u002F Clear your session and sign the user out locally.\n  },\n  on_limit_exceeded: () => {},\n  on_challenge: () => true,\n});\n",[250,406,407,411,427,431,452,471,489,500,517,534,540,557,563,568,583,601],{"__ignoreMap":269},[273,408,409],{"class":275,"line":276},[273,410,333],{"class":279},[273,412,413,415,417,419,421,423,425],{"class":275,"line":283},[273,414,339],{"class":338},[273,416,343],{"class":342},[273,418,346],{"class":338},[273,420,350],{"class":349},[273,422,353],{"class":290},[273,424,356],{"class":349},[273,426,360],{"class":359},[273,428,429],{"class":275,"line":297},[273,430,301],{"emptyLinePlaceholder":300},[273,432,433,436,439,442,445,449],{"class":275,"line":304},[273,434,435],{"class":338},"await",[273,437,343],{"class":438},"sZ9uN",[273,440,441],{"class":359},".",[273,443,400],{"class":444},"sjp9t",[273,446,448],{"class":447},"sJCYa","(",[273,450,451],{"class":359},"{\n",[273,453,454,458,461,463,466,468],{"class":275,"line":310},[273,455,457],{"class":456},"sUwfj","  client_id",[273,459,460],{"class":359},":",[273,462,350],{"class":349},[273,464,465],{"class":290},"your_client_id",[273,467,356],{"class":349},[273,469,470],{"class":359},",\n",[273,472,474,477,479,482,484,487],{"class":275,"line":473},6,[273,475,476],{"class":456},"  account",[273,478,460],{"class":359},[273,480,481],{"class":438}," user",[273,483,441],{"class":359},[273,485,486],{"class":342},"id",[273,488,470],{"class":359},[273,490,492,495,497],{"class":275,"line":491},7,[273,493,494],{"class":456},"  redirect_urls",[273,496,460],{"class":359},[273,498,499],{"class":359}," {\n",[273,501,503,506,508,510,513,515],{"class":275,"line":502},8,[273,504,505],{"class":456},"    logout_url",[273,507,460],{"class":359},[273,509,350],{"class":349},[273,511,512],{"class":290},"https:\u002F\u002Fyourapp.com\u002Flogout",[273,514,356],{"class":349},[273,516,470],{"class":359},[273,518,520,523,525,527,530,532],{"class":275,"line":519},9,[273,521,522],{"class":456},"    new_account_url",[273,524,460],{"class":359},[273,526,350],{"class":349},[273,528,529],{"class":290},"https:\u002F\u002Fyourapp.com\u002Fsignup",[273,531,356],{"class":349},[273,533,470],{"class":359},[273,535,537],{"class":275,"line":536},10,[273,538,539],{"class":359},"  },\n",[273,541,543,546,548,551,555],{"class":275,"line":542},11,[273,544,545],{"class":444},"  on_current_device_logout",[273,547,460],{"class":359},[273,549,550],{"class":359}," ()",[273,552,554],{"class":553},"sHm3x"," =>",[273,556,499],{"class":359},[273,558,560],{"class":275,"line":559},12,[273,561,562],{"class":279},"    \u002F\u002F Clear your session and sign the user out locally.\n",[273,564,566],{"class":275,"line":565},13,[273,567,539],{"class":359},[273,569,571,574,576,578,580],{"class":275,"line":570},14,[273,572,573],{"class":444},"  on_limit_exceeded",[273,575,460],{"class":359},[273,577,550],{"class":359},[273,579,554],{"class":553},[273,581,582],{"class":359}," {},\n",[273,584,586,589,591,593,595,599],{"class":275,"line":585},15,[273,587,588],{"class":444},"  on_challenge",[273,590,460],{"class":359},[273,592,550],{"class":359},[273,594,554],{"class":553},[273,596,598],{"class":597},"s4fYk"," true",[273,600,470],{"class":359},[273,602,604,607,610],{"class":275,"line":603},16,[273,605,606],{"class":359},"}",[273,608,609],{"class":447},")",[273,611,360],{"class":359},[264,613,615],{"className":324,"code":614,"language":326,"meta":269,"style":269},"\u002F\u002F v3\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 Same call site as attach: once per protected page, for paying users.\nawait rupt.evaluate.access({\n  user: user.id,\n  email: user.email,\n  phone: user.phone,\n});\n",[250,616,617,621,637,641,663,678,691,695,699,707,711,716,736,751,767,783],{"__ignoreMap":269},[273,618,619],{"class":275,"line":276},[273,620,369],{"class":279},[273,622,623,625,627,629,631,633,635],{"class":275,"line":283},[273,624,339],{"class":338},[273,626,343],{"class":342},[273,628,346],{"class":338},[273,630,350],{"class":349},[273,632,382],{"class":290},[273,634,356],{"class":349},[273,636,360],{"class":359},[273,638,639],{"class":275,"line":297},[273,640,301],{"emptyLinePlaceholder":300},[273,642,643,646,649,653,657,659,661],{"class":275,"line":304},[273,644,645],{"class":553},"const",[273,647,648],{"class":438}," rupt",[273,650,652],{"class":651},"sut_7"," =",[273,654,656],{"class":655},"srTuz"," new",[273,658,343],{"class":444},[273,660,448],{"class":447},[273,662,451],{"class":359},[273,664,665,668,670,672,674,676],{"class":275,"line":310},[273,666,667],{"class":456},"  clientId",[273,669,460],{"class":359},[273,671,350],{"class":349},[273,673,465],{"class":290},[273,675,356],{"class":349},[273,677,470],{"class":359},[273,679,680,683,685,687,689],{"class":275,"line":473},[273,681,682],{"class":444},"  on_logout",[273,684,460],{"class":359},[273,686,550],{"class":359},[273,688,554],{"class":553},[273,690,499],{"class":359},[273,692,693],{"class":275,"line":491},[273,694,562],{"class":279},[273,696,697],{"class":275,"line":502},[273,698,539],{"class":359},[273,700,701,703,705],{"class":275,"line":519},[273,702,606],{"class":359},[273,704,609],{"class":447},[273,706,360],{"class":359},[273,708,709],{"class":275,"line":536},[273,710,301],{"emptyLinePlaceholder":300},[273,712,713],{"class":275,"line":542},[273,714,715],{"class":279},"\u002F\u002F Same call site as attach: once per protected page, for paying users.\n",[273,717,718,720,722,724,727,729,732,734],{"class":275,"line":559},[273,719,435],{"class":338},[273,721,648],{"class":438},[273,723,441],{"class":359},[273,725,726],{"class":438},"evaluate",[273,728,441],{"class":359},[273,730,731],{"class":444},"access",[273,733,448],{"class":447},[273,735,451],{"class":359},[273,737,738,741,743,745,747,749],{"class":275,"line":565},[273,739,740],{"class":456},"  user",[273,742,460],{"class":359},[273,744,481],{"class":438},[273,746,441],{"class":359},[273,748,486],{"class":342},[273,750,470],{"class":359},[273,752,753,756,758,760,762,765],{"class":275,"line":570},[273,754,755],{"class":456},"  email",[273,757,460],{"class":359},[273,759,481],{"class":438},[273,761,441],{"class":359},[273,763,764],{"class":342},"email",[273,766,470],{"class":359},[273,768,769,772,774,776,778,781],{"class":275,"line":585},[273,770,771],{"class":456},"  phone",[273,773,460],{"class":359},[273,775,481],{"class":438},[273,777,441],{"class":359},[273,779,780],{"class":342},"phone",[273,782,470],{"class":359},[273,784,785,787,789],{"class":275,"line":603},[273,786,606],{"class":359},[273,788,609],{"class":447},[273,790,360],{"class":359},[246,792,793,794,797,798,801],{},"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 ",[250,795,796],{},"auto_challenge: false"," and read ",[250,799,800],{},"response.redirect"," yourself.",[259,803,805],{"id":804},"step-3-recreate-your-policies","Step 3: Recreate your policies",[246,807,808,809,816,817,820],{},"v2 shipped with default account-sharing behavior. In v3 that behavior is explicit: it lives in policies you create in your ",[810,811,815],"a",{"href":812,"rel":813},"https:\u002F\u002Fapp.rupt.dev\u002Fpolicies",[814],"nofollow","policies dashboard",", on the access event. Recreate the three ",[810,818,819],{"href":106},"checks"," v2 came with, each triggering an account-sharing challenge:",[822,823,824,836,844],"ul",{},[825,826,827,831,832,835],"li",{},[828,829,830],"strong",{},"Device limits"," (",[250,833,834],{},"device_count","): more devices than one person uses.",[825,837,838,831,840,843],{},[828,839,129],{},[250,841,842],{},"impossible_travel","): back-to-back activity from locations too far apart to bridge.",[825,845,846,831,848,851],{},[828,847,125],{},[250,849,850],{},"concurrent_sessions","): the account is live in two places at once.",[246,853,854,855,857],{},"Start from these three, then tune to your preference. Until a policy exists on the access event, ",[250,856,396],{}," just gathers signals and never challenges anyone.",[259,859,861],{"id":860},"step-4-set-the-challenge-urls","Step 4: Set the challenge URLs",[246,863,864,865,868,869,871],{},"In v2, ",[250,866,867],{},"redirect_urls"," lived in the ",[250,870,400],{}," call. In v3 they live on the policy's challenge config:",[822,873,874,880],{},[825,875,876,879],{},[828,877,878],{},"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.",[825,881,882,885],{},[828,883,884],{},"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.",[246,887,888,889,892],{},"The Logout URL is not the same as the ",[250,890,891],{},"on_logout"," callback, and account sharing uses both:",[822,894,895,900],{},[825,896,897,899],{},[828,898,884],{}," is a redirect, for the device the user is logging out from on the challenge page.",[825,901,902,906,907,909],{},[828,903,904],{},[250,905,891],{}," 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, ",[250,908,891],{}," is your only hook.",[259,911,913],{"id":912},"what-went-away","What went away",[915,916,917,932],"table",{},[918,919,920],"thead",{},[921,922,923,929],"tr",{},[924,925,926,927,609],"th",{},"v2 (",[250,928,400],{},[924,930,931],{},"v3",[933,934,935,949,961,970,982,996,1009,1029],"tbody",{},[921,936,937,943],{},[938,939,940],"td",{},[250,941,942],{},"client_id",[938,944,945,948],{},[250,946,947],{},"clientId"," on the constructor",[921,950,951,956],{},[938,952,953],{},[250,954,955],{},"account",[938,957,958],{},[250,959,960],{},"user",[921,962,963,967],{},[938,964,965],{},[250,966,867],{},[938,968,969],{},"Success and Logout URLs on the policy's challenge config",[921,971,972,977],{},[938,973,974],{},[250,975,976],{},"on_current_device_logout",[938,978,979,981],{},[250,980,891],{}," on the constructor (or per call)",[921,983,984,989],{},[938,985,986],{},[250,987,988],{},"on_challenge",[938,990,991,992,995],{},"Removed. The challenge auto-redirects (",[250,993,994],{},"auto_challenge"," defaults on for access)",[921,997,998,1003],{},[938,999,1000],{},[250,1001,1002],{},"on_limit_exceeded",[938,1004,1005,1006,1008],{},"Removed. Cap devices with a ",[250,1007,834],{}," policy",[921,1010,1011,1026],{},[938,1012,1013,1016,1017,1016,1020,1016,1023],{},[250,1014,1015],{},"limit_config",", ",[250,1018,1019],{},"tolerance",[250,1021,1022],{},"cookie",[250,1024,1025],{},"secret",[938,1027,1028],{},"Removed from the call. Limits and tolerance are policy-side",[921,1030,1031,1042],{},[938,1032,1033,1016,1036,1016,1039,1041],{},[250,1034,1035],{},"device_id",[250,1037,1038],{},"attached_devices",[250,1040,731],{}," in the response",[938,1043,1044],{},"Not returned. You do not need them client-side",[259,1046,1048],{"id":1047},"related","Related",[822,1050,1051,1056,1061],{},[825,1052,1053,1055],{},[810,1054,35],{"href":36},": the account-sharing fundamental in full.",[825,1057,1058,1060],{},[810,1059,44],{"href":45},": the policies to add.",[825,1062,1063,1066],{},[810,1064,1065],{"href":234},"Account sharing on iOS and Android",": the mobile version of this migration.",[1068,1069,1070],"style",{},"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 pre.shiki code .sHrIR, html code.shiki .sHrIR{--shiki-light:#E2931D;--shiki-default:#61AFEF;--shiki-dark:#A6E22E}html pre.shiki code .siibJ, html code.shiki .siibJ{--shiki-light:#91B859;--shiki-default:#98C379;--shiki-dark:#E6DB74}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 .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 .shEKG, html code.shiki .shEKG{--shiki-light:#39ADB5;--shiki-default:#ABB2BF;--shiki-dark:#F8F8F2}html pre.shiki code .sZ9uN, html code.shiki .sZ9uN{--shiki-light:#90A4AE;--shiki-default:#E5C07B;--shiki-dark:#F8F8F2}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 .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 .s4fYk, html code.shiki .s4fYk{--shiki-light:#FF5370;--shiki-default:#D19A66;--shiki-dark:#AE81FF}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}",{"title":269,"searchDepth":283,"depth":283,"links":1072},[1073,1074,1075,1076,1077,1078],{"id":261,"depth":283,"text":262},{"id":389,"depth":283,"text":390},{"id":804,"depth":283,"text":805},{"id":860,"depth":283,"text":861},{"id":912,"depth":283,"text":913},{"id":1047,"depth":283,"text":1048},"Move the v2 web account-sharing integration onto v3. Swap the package, create a client, and replace Rupt.attach with rupt.evaluate.access from the same call site.","md",{},"---\ntitle: Account sharing on web\ndescription: Move the v2 web account-sharing integration onto v3. Swap the package, create a client, and replace Rupt.attach with rupt.evaluate.access from the same call site.\n---\n\n# Account sharing on web\n\nAccount 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.\n\n## Step 1: Swap the package\n\n```sh\n# remove the v2 package\nnpm uninstall rupt\n\n# add the v3 client\nnpm install @ruptjs\u002Fclient\n```\n\nThen update the import:\n\n```js\n\u002F\u002F v2\nimport Rupt from \"rupt\";\n\n\u002F\u002F v3\nimport Rupt from \"@ruptjs\u002Fclient\";\n```\n\n## Step 2: Create a client, then evaluate\n\nv2 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.\n\n```js\n\u002F\u002F v2\nimport Rupt from \"rupt\";\n\nawait Rupt.attach({\n  client_id: \"your_client_id\",\n  account: user.id,\n  redirect_urls: {\n    logout_url: \"https:\u002F\u002Fyourapp.com\u002Flogout\",\n    new_account_url: \"https:\u002F\u002Fyourapp.com\u002Fsignup\",\n  },\n  on_current_device_logout: () => {\n    \u002F\u002F Clear your session and sign the user out locally.\n  },\n  on_limit_exceeded: () => {},\n  on_challenge: () => true,\n});\n```\n\n```js\n\u002F\u002F v3\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 Same call site as attach: once per protected page, for paying users.\nawait rupt.evaluate.access({\n  user: user.id,\n  email: user.email,\n  phone: user.phone,\n});\n```\n\nWhen 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.\n\n## Step 3: Recreate your policies\n\nv2 shipped with default account-sharing behavior. In v3 that behavior is explicit: it lives in policies you create in your [policies dashboard](https:\u002F\u002Fapp.rupt.dev\u002Fpolicies), on the access event. Recreate the three [checks](\u002Fdocs\u002Fv3\u002Fconcepts\u002Fchecks) v2 came with, each triggering an account-sharing challenge:\n\n- **Device limits** (`device_count`): more devices than one person uses.\n- **Impossible travel** (`impossible_travel`): back-to-back activity from locations too far apart to bridge.\n- **Concurrency** (`concurrent_sessions`): the account is live in two places at once.\n\nStart 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.\n\n## Step 4: Set the challenge URLs\n\nIn v2, `redirect_urls` lived in the `attach` call. In v3 they live on the policy's challenge config:\n\n- **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.\n- **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.\n\nThe Logout URL is not the same as the `on_logout` callback, and account sharing uses both:\n\n- **Logout URL** is a redirect, for the device the user is logging out from on the challenge page.\n- **`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.\n\n## What went away\n\n| v2 (`attach`)                                   | v3                                                                 |\n| ----------------------------------------------- | ------------------------------------------------------------------ |\n| `client_id`                                     | `clientId` on the constructor                                      |\n| `account`                                       | `user`                                                             |\n| `redirect_urls`                                 | Success and Logout URLs on the policy's challenge config           |\n| `on_current_device_logout`                      | `on_logout` on the constructor (or per call)                       |\n| `on_challenge`                                  | Removed. The challenge auto-redirects (`auto_challenge` defaults on for access) |\n| `on_limit_exceeded`                             | Removed. Cap devices with a `device_count` policy                  |\n| `limit_config`, `tolerance`, `cookie`, `secret` | Removed from the call. Limits and tolerance are policy-side        |\n| `device_id`, `attached_devices`, `access` in the response | Not returned. You do not need them client-side              |\n\n## Related\n\n- [Access protection](\u002Fdocs\u002Fv3\u002Ffundamentals\u002Faccess-protection): the account-sharing fundamental in full.\n- [Account sharing prevention](\u002Fdocs\u002Fv3\u002Fguides\u002Faccount-sharing-prevention): the policies to add.\n- [Account sharing on iOS and Android](\u002Fdocs\u002Fv3\u002Fmigration\u002Faccount-sharing-on-mobile): the mobile version of this migration.\n",{"title":229,"description":1079},"XLH1s2G7bKz9oNh_FFs7T3ysQZHbDs57nITwpR32dSA",1782933210060]