[{"data":1,"prerenderedAt":742},["ShallowReactive",2],{"navigation":3,"\u002Fgetting-started\u002Fbrowser-clients":214,"\u002Fgetting-started\u002Fbrowser-clients-surround":737},[4,43,105,113,188],{"title":5,"path":6,"stem":7,"children":8,"icon":42},"Get started","\u002Fgetting-started","1.getting-started\u002F1.index",[9,12,17,22,27,32,37],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","i-lucide-house",{"title":13,"path":14,"stem":15,"icon":16},"Install","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":18,"path":19,"stem":20,"icon":21},"Quick start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start","i-lucide-play",{"title":23,"path":24,"stem":25,"icon":26},"Choose your setup","\u002Fgetting-started\u002Fchoose-a-sign-in-stack","1.getting-started\u002F4.choose-a-sign-in-stack","i-lucide-signpost",{"title":28,"path":29,"stem":30,"icon":31},"Browser clients","\u002Fgetting-started\u002Fbrowser-clients","1.getting-started\u002F5.browser-clients","i-lucide-globe",{"title":33,"path":34,"stem":35,"icon":36},"Coding agents","\u002Fgetting-started\u002Fai-agents","1.getting-started\u002F6.ai-agents","i-lucide-bot",{"title":38,"path":39,"stem":40,"icon":41},"Upgrade from 3.x","\u002Fgetting-started\u002Fupgrading-to-4","1.getting-started\u002F8.upgrading-to-4","i-lucide-arrow-up-right","i-lucide-rocket",{"title":44,"icon":45,"path":46,"stem":47,"children":48,"page":104},"Guides","i-lucide-waypoints","\u002Fguides","2.guides",[49,54,59,64,69,74,79,84,89,94,99],{"title":50,"path":51,"stem":52,"icon":53},"Register users","\u002Fguides\u002Fregistration","2.guides\u002F02.registration","i-lucide-user-plus",{"title":55,"path":56,"stem":57,"icon":58},"Sign users in","\u002Fguides\u002Fsign-in","2.guides\u002F03.sign-in","i-lucide-log-in",{"title":60,"path":61,"stem":62,"icon":63},"Sign users out","\u002Fguides\u002Fsign-out","2.guides\u002F04.sign-out","i-lucide-log-out",{"title":65,"path":66,"stem":67,"icon":68},"Two-factor auth","\u002Fguides\u002Ftwo-factor","2.guides\u002F05.two-factor","i-lucide-smartphone",{"title":70,"path":71,"stem":72,"icon":73},"Email-code sign-in","\u002Fguides\u002Femail-code","2.guides\u002F06.email-code","i-lucide-mail",{"title":75,"path":76,"stem":77,"icon":78},"Reset a password","\u002Fguides\u002Freset-password","2.guides\u002F07.reset-password","i-lucide-key-round",{"title":80,"path":81,"stem":82,"icon":83},"Manage account","\u002Fguides\u002Fmanage-account","2.guides\u002F08.manage-account","i-lucide-user-cog",{"title":85,"path":86,"stem":87,"icon":88},"Manage passkeys","\u002Fguides\u002Fmanage-passkeys","2.guides\u002F09.manage-passkeys","i-lucide-scan-face",{"title":90,"path":91,"stem":92,"icon":93},"Link accounts","\u002Fguides\u002Flink-external-accounts","2.guides\u002F10.link-external-accounts","i-lucide-link",{"title":95,"path":96,"stem":97,"icon":98},"Require step-up","\u002Fguides\u002Fstep-up","2.guides\u002F11.step-up","i-lucide-shield-check",{"title":100,"path":101,"stem":102,"icon":103},"No public sign-up","\u002Fguides\u002Finternal-app","2.guides\u002F12.internal-app","i-lucide-building-2",false,{"title":106,"path":107,"stem":108,"children":109,"icon":112},"Composables","\u002Fcomposables","3.composables\u002F1.index",[110],{"title":111,"path":107,"stem":108,"icon":112},"Build a custom stack","i-lucide-blocks",{"title":114,"icon":115,"path":116,"stem":117,"children":118,"page":104},"Reference","i-lucide-book-open","\u002Fmodules","4.modules",[119,124,128,133,137,142,147,152,156,161,165,170,174,179,184],{"title":120,"path":121,"stem":122,"icon":123},"Endpoint reference","\u002Fmodules\u002Fendpoints","4.modules\u002F01.endpoints","i-lucide-route",{"title":125,"path":126,"stem":127,"icon":78},"Password auth","\u002Fmodules\u002Fpassword-auth","4.modules\u002F02.password-auth",{"title":129,"path":130,"stem":131,"icon":132},"Composition table","\u002Fmodules\u002Fcomposition","4.modules\u002F03.composition","i-lucide-table",{"title":134,"path":135,"stem":136,"icon":83},"Identity module","\u002Fmodules\u002Fidentity-management","4.modules\u002F04.identity-management",{"title":138,"path":139,"stem":140,"icon":141},"Cookie sign-in","\u002Fmodules\u002Fcookie-auth","4.modules\u002F05.cookie-auth","i-lucide-cookie",{"title":143,"path":144,"stem":145,"icon":146},"Identity bearer","\u002Fmodules\u002Fbearer-auth","4.modules\u002F06.bearer-auth","i-lucide-key",{"title":148,"path":149,"stem":150,"icon":151},"JWT","\u002Fmodules\u002Fjwt","4.modules\u002F07.jwt","i-lucide-fingerprint",{"title":153,"path":154,"stem":155,"icon":88},"Passkeys","\u002Fmodules\u002Fpasskeys","4.modules\u002F08.passkeys",{"title":157,"path":158,"stem":159,"icon":160},"Step-up ReAuth","\u002Fmodules\u002Freauth","4.modules\u002F09.reauth","i-lucide-shield-alert",{"title":162,"path":163,"stem":164,"icon":58},"External OAuth","\u002Fmodules\u002Fexternal-oauth","4.modules\u002F10.external-oauth",{"title":166,"path":167,"stem":168,"icon":169},"Configuration","\u002Fmodules\u002Fconfiguration","4.modules\u002F11.configuration","i-lucide-settings",{"title":171,"path":172,"stem":173,"icon":98},"CSRF rules","\u002Fmodules\u002Fcsrf","4.modules\u002F12.csrf",{"title":175,"path":176,"stem":177,"icon":178},"Responses","\u002Fmodules\u002Ferrors","4.modules\u002F13.errors","i-lucide-circle-alert",{"title":180,"path":181,"stem":182,"icon":183},"Rate-limit policies","\u002Fmodules\u002Frate-limits","4.modules\u002F14.rate-limits","i-lucide-gauge",{"title":185,"path":186,"stem":187,"icon":73},"Email codes","\u002Fmodules\u002Femail-code","4.modules\u002F15.email-code",{"title":189,"icon":190,"path":191,"stem":192,"children":193,"page":104},"Concepts","i-lucide-lightbulb","\u002Fconcepts","5.concepts",[194,199,204,209],{"title":195,"path":196,"stem":197,"icon":198},"Comparison","\u002Fconcepts\u002Fcompare","5.concepts\u002F1.compare","i-lucide-git-compare",{"title":200,"path":201,"stem":202,"icon":203},"Security model","\u002Fconcepts\u002Fsecurity-model","5.concepts\u002F2.security-model","i-lucide-shield",{"title":205,"path":206,"stem":207,"icon":208},"Production","\u002Fconcepts\u002Fproduction","5.concepts\u002F3.production","i-lucide-factory",{"title":210,"path":211,"stem":212,"icon":213},"FAQ","\u002Fconcepts\u002Ffaq","5.concepts\u002F4.faq","i-lucide-circle-help",{"id":215,"title":216,"body":217,"description":730,"extension":731,"faq":104,"links":732,"meta":733,"navigation":734,"path":29,"seo":735,"stem":30,"__hash__":736},"docs\u002F1.getting-started\u002F5.browser-clients.md","Call the API from a browser",{"type":218,"value":219,"toc":723},"minimark",[220,224,229,245,249,288,372,381,385,388,587,596,600,607,664,691,695,719],[221,222,223],"p",{},"Browser clients on the cookie stack and the JWT stack depend on cookies and antiforgery tokens. Follow these steps for a single-page app (SPA) or any other browser client.",[225,226,228],"h2",{"id":227},"send-cookies-on-every-request","Send cookies on every request",[221,230,231,232,236,237,240,241,244],{},"Add ",[233,234,235],"code",{},"credentials: 'include'"," to every ",[233,238,239],{},"fetch"," call. With Axios, set ",[233,242,243],{},"withCredentials: true",". Without it, the browser does not send the application cookie, the antiforgery cookie, the ReAuth cookie, or the JWT refresh cookie.",[225,246,248],{"id":247},"send-a-csrf-token-on-protected-requests","Send a CSRF token on protected requests",[250,251,252,270,277],"ol",{},[253,254,255,256,259,260,263,264,269],"li",{},"Get a token. The password facade serves it at ",[233,257,258],{},"GET \u002Fauth\u002FcsrfToken"," for a cookie session and for JWT cookie refresh. The route returns ",[233,261,262],{},"{ \"csrfToken\": \"...\" }"," and set the antiforgery cookie. JWT body refresh maps no token route. The full list is in ",[265,266,268],"a",{"href":267},"\u002Fmodules\u002Fcsrf\u002F","Antiforgery (CSRF) rules",".",[253,271,272,273,276],{},"Send the token in the ",[233,274,275],{},"RequestVerificationToken"," header on every route that requires antiforgery.",[253,278,279,280,283,284,287],{},"If a request returns ",[233,281,282],{},"400"," with the body ",[233,285,286],{},"Invalid or missing CSRF token.",", get a new token and retry once.",[289,290,295],"pre",{"className":291,"code":292,"language":293,"meta":294,"style":294},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","async function csrf() {\n  const r = await fetch('\u002Fauth\u002FcsrfToken', { credentials: 'include' });\n  return (await r.json()).csrfToken;\n}\n\nconst csrfToken = await csrf();\nawait fetch('\u002Fauth\u002Fmanage\u002Finfo', {\n  method: 'POST',\n  credentials: 'include',\n  headers: { 'Content-Type': 'application\u002Fjson', 'RequestVerificationToken': csrfToken },\n  body: JSON.stringify({ newEmail })\n});\n","js","",[233,296,297,305,311,317,323,330,336,342,348,354,360,366],{"__ignoreMap":294},[298,299,302],"span",{"class":300,"line":301},"line",1,[298,303,304],{},"async function csrf() {\n",[298,306,308],{"class":300,"line":307},2,[298,309,310],{},"  const r = await fetch('\u002Fauth\u002FcsrfToken', { credentials: 'include' });\n",[298,312,314],{"class":300,"line":313},3,[298,315,316],{},"  return (await r.json()).csrfToken;\n",[298,318,320],{"class":300,"line":319},4,[298,321,322],{},"}\n",[298,324,326],{"class":300,"line":325},5,[298,327,329],{"emptyLinePlaceholder":328},true,"\n",[298,331,333],{"class":300,"line":332},6,[298,334,335],{},"const csrfToken = await csrf();\n",[298,337,339],{"class":300,"line":338},7,[298,340,341],{},"await fetch('\u002Fauth\u002Fmanage\u002Finfo', {\n",[298,343,345],{"class":300,"line":344},8,[298,346,347],{},"  method: 'POST',\n",[298,349,351],{"class":300,"line":350},9,[298,352,353],{},"  credentials: 'include',\n",[298,355,357],{"class":300,"line":356},10,[298,358,359],{},"  headers: { 'Content-Type': 'application\u002Fjson', 'RequestVerificationToken': csrfToken },\n",[298,361,363],{"class":300,"line":362},11,[298,364,365],{},"  body: JSON.stringify({ newEmail })\n",[298,367,369],{"class":300,"line":368},12,[298,370,371],{},"});\n",[221,373,374,375,378,379,269],{},"The token is tied to the signed-in user. After sign-in or sign-out, get a new token. Login, register, forgot password, and reset password need no token. A request that sends the access token in ",[233,376,377],{},"Authorization: Bearer"," skips the check when the application cookie is absent. If the host reads that token from a cookie, send the CSRF token. The full list is in ",[265,380,268],{"href":267},[225,382,384],{"id":383},"set-up-cors-when-the-client-runs-on-another-origin","Set up CORS when the client runs on another origin",[221,386,387],{},"AuthEndpoints does not configure CORS. If the browser client and the API have different origins, add a CORS policy in the host that allows credentials and the AuthEndpoints headers:",[289,389,393],{"className":390,"code":391,"language":392,"meta":294,"style":294},"language-cs shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","builder.Services.AddCors(o => o.AddPolicy(\"spa\", policy => policy\n    .WithOrigins(\"https:\u002F\u002Fapp.example.com\")\n    .AllowCredentials()\n    .AllowAnyMethod()\n    .WithHeaders(\"Content-Type\", \"RequestVerificationToken\", \"X-AuthEndpoints-Reauth\")));\n\nvar app = builder.Build();\napp.UseCors(\"spa\");\napp.UseAuthEndpoints();\n","cs",[233,394,395,453,473,483,492,529,533,555,576],{"__ignoreMap":294},[298,396,397,401,404,407,409,413,416,420,423,426,428,431,433,436,440,442,445,448,450],{"class":300,"line":301},[298,398,400],{"class":399},"sTEyZ","builder",[298,402,269],{"class":403},"sMK4o",[298,405,406],{"class":399},"Services",[298,408,269],{"class":403},[298,410,412],{"class":411},"s2Zo4","AddCors",[298,414,415],{"class":403},"(",[298,417,419],{"class":418},"sBMFI","o",[298,421,422],{"class":403}," =>",[298,424,425],{"class":399}," o",[298,427,269],{"class":403},[298,429,430],{"class":411},"AddPolicy",[298,432,415],{"class":403},[298,434,435],{"class":403},"\"",[298,437,439],{"class":438},"sfazB","spa",[298,441,435],{"class":403},[298,443,444],{"class":403},",",[298,446,447],{"class":418}," policy",[298,449,422],{"class":403},[298,451,452],{"class":399}," policy\n",[298,454,455,458,461,463,465,468,470],{"class":300,"line":307},[298,456,457],{"class":403},"    .",[298,459,460],{"class":411},"WithOrigins",[298,462,415],{"class":403},[298,464,435],{"class":403},[298,466,467],{"class":438},"https:\u002F\u002Fapp.example.com",[298,469,435],{"class":403},[298,471,472],{"class":403},")\n",[298,474,475,477,480],{"class":300,"line":313},[298,476,457],{"class":403},[298,478,479],{"class":411},"AllowCredentials",[298,481,482],{"class":403},"()\n",[298,484,485,487,490],{"class":300,"line":319},[298,486,457],{"class":403},[298,488,489],{"class":411},"AllowAnyMethod",[298,491,482],{"class":403},[298,493,494,496,499,501,503,506,508,510,513,515,517,519,521,524,526],{"class":300,"line":325},[298,495,457],{"class":403},[298,497,498],{"class":411},"WithHeaders",[298,500,415],{"class":403},[298,502,435],{"class":403},[298,504,505],{"class":438},"Content-Type",[298,507,435],{"class":403},[298,509,444],{"class":403},[298,511,512],{"class":403}," \"",[298,514,275],{"class":438},[298,516,435],{"class":403},[298,518,444],{"class":403},[298,520,512],{"class":403},[298,522,523],{"class":438},"X-AuthEndpoints-Reauth",[298,525,435],{"class":403},[298,527,528],{"class":403},")));\n",[298,530,531],{"class":300,"line":332},[298,532,329],{"emptyLinePlaceholder":328},[298,534,535,538,541,544,547,549,552],{"class":300,"line":338},[298,536,537],{"class":418},"var",[298,539,540],{"class":418}," app",[298,542,543],{"class":403}," =",[298,545,546],{"class":399}," builder",[298,548,269],{"class":403},[298,550,551],{"class":411},"Build",[298,553,554],{"class":403},"();\n",[298,556,557,560,562,565,567,569,571,573],{"class":300,"line":344},[298,558,559],{"class":399},"app",[298,561,269],{"class":403},[298,563,564],{"class":411},"UseCors",[298,566,415],{"class":403},[298,568,435],{"class":403},[298,570,439],{"class":438},[298,572,435],{"class":403},[298,574,575],{"class":403},");\n",[298,577,578,580,582,585],{"class":300,"line":350},[298,579,559],{"class":399},[298,581,269],{"class":403},[298,583,584],{"class":411},"UseAuthEndpoints",[298,586,554],{"class":403},[221,588,589,591,592,595],{},[233,590,479],{}," does not work with ",[233,593,594],{},"AllowAnyOrigin",". List the exact origins.",[225,597,599],{"id":598},"keep-the-client-and-the-api-on-the-same-site","Keep the client and the API on the same site",[221,601,602,603,606],{},"CORS lets the request through, but cookie ",[233,604,605],{},"SameSite"," rules decide which cookies the browser sends:",[608,609,610,624],"table",{},[611,612,613],"thead",{},[614,615,616,620],"tr",{},[617,618,619],"th",{},"Cookie",[617,621,622],{},[233,623,605],{},[625,626,627,641,653],"tbody",{},[614,628,629,635],{},[630,631,632],"td",{},[233,633,634],{},".AspNetCore.Identity.Application",[630,636,637,640],{},[233,638,639],{},"Lax"," (Identity default)",[614,642,643,648],{},[630,644,645],{},[233,646,647],{},"AuthEndpoints.ReAuth",[630,649,650],{},[233,651,652],{},"Strict",[614,654,655,660],{},[630,656,657],{},[233,658,659],{},"AuthEndpoints.Jwt.RefreshToken",[630,661,662],{},[233,663,652],{},[221,665,666,669,670,673,674,677,678,681,682,684,685,687,688,690],{},[233,667,668],{},"app.example.com"," and ",[233,671,672],{},"api.example.com"," are the same site, so these cookies work. A client on a different registrable domain, such as ",[233,675,676],{},"example-app.com"," calling ",[233,679,680],{},"example.com",", is cross-site. The browser does not send ",[233,683,639],{}," or ",[233,686,652],{}," cookies on cross-site ",[233,689,239],{}," calls. Serve the API under the same site as the client, or put a reverse proxy in front of it.",[225,692,694],{"id":693},"related","Related",[696,697,698,702,707,713],"ul",{},[253,699,700],{},[265,701,268],{"href":267},[253,703,704],{},[265,705,55],{"href":706},"\u002Fguides\u002Fsign-in\u002F",[253,708,709],{},[265,710,712],{"href":711},"\u002Fmodules\u002Fcookie-auth\u002F","Cookie sign-in module",[253,714,715],{},[265,716,718],{"href":717},"\u002Fmodules\u002Fjwt\u002F","JWT module",[720,721,722],"style",{},"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 .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":294,"searchDepth":301,"depth":307,"links":724},[725,726,727,728,729],{"id":227,"depth":307,"text":228},{"id":247,"depth":307,"text":248},{"id":383,"depth":307,"text":384},{"id":598,"depth":307,"text":599},{"id":693,"depth":307,"text":694},"Send cookies and CSRF tokens from a browser client, and set up CORS when the client runs on another origin.","md",null,{},{"title":28,"icon":31},{"title":216,"description":730},"NMafAVdvn7FXsJZY_RX8xI8B9XNlrje-yeIl5BB5hM8",[738,740],{"title":23,"path":24,"stem":25,"description":739,"icon":26,"children":-1},"Match a client and a sign-in method to one AuthEndpoints call, then open the page that shows that call.",{"title":33,"path":34,"stem":35,"description":741,"icon":36,"children":-1},"Add the AuthEndpoints skill to your app so that coding agents follow the library's conventions.",1792403032052]