[{"data":1,"prerenderedAt":574},["ShallowReactive",2],{"navigation":3,"\u002Fconcepts\u002Fproduction":214,"\u002Fconcepts\u002Fproduction-surround":569},[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":562,"extension":563,"faq":104,"links":564,"meta":565,"navigation":566,"path":206,"seo":567,"stem":207,"__hash__":568},"docs\u002F5.concepts\u002F3.production.md","Prepare for production",{"type":218,"value":219,"toc":550},"minimark",[220,224,229,269,273,276,350,354,357,389,393,396,428,432,448,452,516,520],[221,222,223],"p",{},"Work through this checklist before you deploy. Startup validation catches some items. The rest are your responsibility.",[225,226,228],"h2",{"id":227},"check-the-core-settings","Check the core settings",[230,231,232,236,252,259],"ul",{},[233,234,235],"li",{},"Serve the API over HTTPS.",[233,237,238,239,243,244,247,248,251],{},"Register a real ",[240,241,242],"code",{},"IEmailSender\u003CTUser>",". When ",[240,245,246],{},"RequireEmailSenderInProduction"," is ",[240,249,250],{},"true"," (the default), startup fails in Production while Identity's no-op sender is registered.",[233,253,254,255,258],{},"On the password facade, set ",[240,256,257],{},"Passkeys.ServerDomain"," only when you want passkeys. Leave it unset to keep them off. A whitespace value fails startup in Production.",[233,260,261,262,265,266,268],{},"Leave ",[240,263,264],{},"RequireConfirmedAccount"," at ",[240,267,250],{}," unless you have another way to verify email ownership.",[225,270,272],{"id":271},"check-the-email-code-settings","Check the email-code settings",[221,274,275],{},"Skip this section if email-code sign-in is off.",[230,277,278,293,312,326,344],{},[233,279,280,281,284,285,288,289,292],{},"Call ",[240,282,283],{},"modelBuilder.UseEmailCodes()"," and apply the migration. ",[240,286,287],{},"MapEmailCodeEndpoints"," throws without that entity. The table is ",[240,290,291],{},"AuthEndpoints.AuthEndpointsEmailCodes",".",[233,294,238,295,298,299,301,302,305,306,247,309,292],{},[240,296,297],{},"IEmailCodeSender\u003CTUser>",". ",[240,300,242],{}," does not send the code. Outside Development, startup fails while ",[240,303,304],{},"DevelopmentEmailCodeSender\u003CTUser>"," or no sender is registered, unless ",[240,307,308],{},"RequireSenderOutsideDevelopment",[240,310,311],{},"false",[233,313,314,315,298,318,321,322,325],{},"Queue the message and return. Send awaits ",[240,316,317],{},"SendSignInCodeAsync",[240,319,320],{},"Code"," and ",[240,323,324],{},"LinkUrl"," are raw. Encode them in an HTML template, and do not log them.",[233,327,328,329,332,333,336,337,340,341,292],{},"If the magic link is on, set ",[240,330,331],{},"LinkUri"," to an absolute ",[240,334,335],{},"https"," URI with no ",[240,338,339],{},"#",", and list that origin in ",[240,342,343],{},"MagicLink.AllowedOrigins",[233,345,261,346,349],{},[240,347,348],{},"AllowSignUp"," off unless an unknown address should become a confirmed user with no password.",[225,351,353],{"id":352},"check-the-jwt-settings","Check the JWT settings",[221,355,356],{},"Skip this section if JWT is off.",[230,358,359,369,379,382],{},[233,360,280,361,364,365,368],{},[240,362,363],{},"modelBuilder.UseRefreshToken()"," on your ",[240,366,367],{},"DbContext"," and apply the migration.",[233,370,371,372,321,375,378],{},"Set an issuer and an audience. Startup fails in Production with the library defaults (",[240,373,374],{},"Jwt",[240,376,377],{},"JwtAudience",").",[233,380,381],{},"Use a symmetric key of at least 256 bits (32 UTF-8 bytes), or an asymmetric key.",[233,383,384,385,388],{},"If you upgrade from plaintext refresh-token storage, recreate the ",[240,386,387],{},"AuthEndpointsRefreshTokens"," table. AuthEndpoints now stores hashed tokens with reuse detection.",[225,390,392],{"id":391},"check-the-external-oauth-settings","Check the external OAuth settings",[221,394,395],{},"Skip this section if you do not use GitHub or Google.",[230,397,398,405,415,421],{},[233,399,400,401,404],{},"Map the OAuth routes yourself. ",[240,402,403],{},"MapAuthEndpoints"," does not map them.",[233,406,407,408,411,412,378],{},"Host a page at ",[240,409,410],{},"ErrorPath"," (default ",[240,413,414],{},"\u002Fauth\u002Fexternal\u002Ferror",[233,416,261,417,420],{},[240,418,419],{},"AutoLinkByEmail"," off unless a verified provider email should attach to an existing confirmed account.",[233,422,423,424,427],{},"Keep ",[240,425,426],{},"RequireVerifiedEmail"," on.",[225,429,431],{"id":430},"check-the-browser-setup","Check the browser setup",[230,433,434,442],{},[233,435,436,437,292],{},"If the client runs on another origin, add a CORS policy with credentials. See ",[438,439,441],"a",{"href":440},"\u002Fgetting-started\u002Fbrowser-clients\u002F","Call the API from a browser",[233,443,444,445,292],{},"Decide whether passkey and OAuth sign-in skipping 2FA fits your threat model. See ",[438,446,200],{"href":447},"\u002Fconcepts\u002Fsecurity-model\u002F",[225,449,451],{"id":450},"what-the-validators-check","What the validators check",[230,453,454,472,478,490,496,499],{},[233,455,456,459,460,463,464,467,468,471],{},[240,457,458],{},"AuthEndpointsOptionsValidator"," checks ",[240,461,462],{},"IdentityPath",", ",[240,465,466],{},"PasskeyPath",", and ",[240,469,470],{},"Jwt.Path"," formats, and the Production passkey domain.",[233,473,474,477],{},[240,475,476],{},"AuthEndpointsEmailSenderValidator"," checks the email sender in Production.",[233,479,480,459,483,485,486,247,488,292],{},[240,481,482],{},"EmailCodeSenderValidator\u003CTUser>",[240,484,297],{}," outside Development when email-code sign-in is registered and ",[240,487,308],{},[240,489,250],{},[233,491,492,495],{},[240,493,494],{},"EmailCodeOptionsValidator"," checks code length, lifetime, attempts, cooldown, send caps, and the magic-link URI.",[233,497,498],{},"JWT options validation rejects the default issuer and audience in Production, and checks the key material against the signing algorithm.",[233,500,501,321,504,507,508,511,512,515],{},[240,502,503],{},"AddGitHub",[240,505,506],{},"AddGoogle"," reject an empty ",[240,509,510],{},"ClientId"," or ",[240,513,514],{},"ClientSecret"," at startup.",[225,517,519],{"id":518},"related","Related",[230,521,522,528,534,540,546],{},[233,523,524],{},[438,525,527],{"href":526},"\u002Fmodules\u002Fconfiguration\u002F","Configuration options",[233,529,530],{},[438,531,533],{"href":532},"\u002Fmodules\u002Femail-code\u002F","Email-code module",[233,535,536],{},[438,537,539],{"href":538},"\u002Fmodules\u002Fjwt\u002F","JWT module",[233,541,542],{},[438,543,545],{"href":544},"\u002Fmodules\u002Fpasskeys\u002F","Passkeys module",[233,547,548],{},[438,549,200],{"href":447},{"title":551,"searchDepth":552,"depth":553,"links":554},"",1,2,[555,556,557,558,559,560,561],{"id":227,"depth":553,"text":228},{"id":271,"depth":553,"text":272},{"id":352,"depth":553,"text":353},{"id":391,"depth":553,"text":392},{"id":430,"depth":553,"text":431},{"id":450,"depth":553,"text":451},{"id":518,"depth":553,"text":519},"Checklist for deploying AuthEndpoints: HTTPS, core settings, email codes, JWT, GitHub and Google OAuth, browser setup, and startup validation.","md",null,{},{"title":205,"icon":208},{"title":216,"description":562},"Yyz1jd_uC3SvBuTKDtwIoahIvqhiiYcfNfSfhKfaE-w",[570,572],{"title":200,"path":201,"stem":202,"description":571,"icon":203,"children":-1},"How AuthEndpoints hides which accounts exist, finishes each sign-in in a session, protects account changes, and which trade-offs it leaves to the host.",{"title":210,"path":211,"stem":212,"description":573,"icon":213,"children":-1},"Does AuthEndpoints replace Identity? Cookies, JWT, or opaque bearer tokens? Logout, chosen routes, and passkeys compared with MapIdentityApi.",1792403035815]