[{"data":1,"prerenderedAt":2027},["ShallowReactive",2],{"navigation":3,"\u002Fmodules\u002Femail-code":250,"\u002Fmodules\u002Femail-code-surround":2022},[4,43,120,143,219],{"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 AuthEndpoints","\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},"Pick 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},"Use the AuthEndpoints skill with coding agents","\u002Fgetting-started\u002Fai-agents","1.getting-started\u002F5.ai-agents","i-lucide-bot",{"title":33,"path":34,"stem":35,"icon":36},"Password auth","\u002Fgetting-started\u002Fpassword-auth","1.getting-started\u002F6.password-auth","i-lucide-key-round",{"title":38,"path":39,"stem":40,"icon":41},"3.x facade","\u002Fgetting-started\u002Fcompatibility-facade","1.getting-started\u002F7.compatibility-facade","i-lucide-archive","i-lucide-rocket",{"title":44,"path":45,"stem":46,"children":47,"icon":119},"Guides","\u002Fguides","2.guides\u002F01.index",[48,50,55,60,65,70,74,79,84,89,94,99,104,109,114],{"title":44,"path":45,"stem":46,"icon":49},"i-lucide-list-checks",{"title":51,"path":52,"stem":53,"icon":54},"Register users","\u002Fguides\u002Fregistration","2.guides\u002F02.registration","i-lucide-user-plus",{"title":56,"path":57,"stem":58,"icon":59},"Sign users in","\u002Fguides\u002Fsign-in","2.guides\u002F03.sign-in","i-lucide-log-in",{"title":61,"path":62,"stem":63,"icon":64},"Sign users out","\u002Fguides\u002Fsign-out","2.guides\u002F04.sign-out","i-lucide-log-out",{"title":66,"path":67,"stem":68,"icon":69},"Turn on two-factor authentication","\u002Fguides\u002Ftwo-factor","2.guides\u002F05.two-factor","i-lucide-smartphone",{"title":71,"path":72,"stem":73,"icon":36},"Reset a forgotten password","\u002Fguides\u002Freset-password","2.guides\u002F06.reset-password",{"title":75,"path":76,"stem":77,"icon":78},"Change a user's email or password","\u002Fguides\u002Fmanage-account","2.guides\u002F07.manage-account","i-lucide-user-cog",{"title":80,"path":81,"stem":82,"icon":83},"Add, rename, and remove passkeys","\u002Fguides\u002Fmanage-passkeys","2.guides\u002F08.manage-passkeys","i-lucide-scan-face",{"title":85,"path":86,"stem":87,"icon":88},"Link and unlink GitHub or Google accounts","\u002Fguides\u002Flink-external-accounts","2.guides\u002F09.link-external-accounts","i-lucide-link",{"title":90,"path":91,"stem":92,"icon":93},"Require step-up before sensitive actions","\u002Fguides\u002Fstep-up","2.guides\u002F10.step-up","i-lucide-shield-check",{"title":95,"path":96,"stem":97,"icon":98},"Call the API from a browser","\u002Fguides\u002Fbrowser-clients","2.guides\u002F11.browser-clients","i-lucide-globe",{"title":100,"path":101,"stem":102,"icon":103},"Prepare for production","\u002Fguides\u002Fproduction","2.guides\u002F12.production","i-lucide-factory",{"title":105,"path":106,"stem":107,"icon":108},"Sign in with an emailed code","\u002Fguides\u002Femail-code","2.guides\u002F13.email-code","i-lucide-mail",{"title":110,"path":111,"stem":112,"icon":113},"Upgrade to 4.0","\u002Fguides\u002Fupgrading-to-4","2.guides\u002F14.upgrading-to-4","i-lucide-arrow-up-right",{"title":115,"path":116,"stem":117,"icon":118},"Run an app with no public sign-up","\u002Fguides\u002Finternal-app","2.guides\u002F15.internal-app","i-lucide-building-2","i-lucide-waypoints",{"title":121,"path":122,"stem":123,"children":124,"icon":142},"Composable endpoints","\u002Fcomposables","3.composables\u002F1.index",[125,128,132,137],{"title":126,"path":122,"stem":123,"icon":127},"How composition works","i-lucide-layout-grid",{"title":129,"path":130,"stem":131,"icon":49},"Composition requirements","\u002Fcomposables\u002Frequirements","3.composables\u002F2.requirements",{"title":133,"path":134,"stem":135,"icon":136},"Compose a custom auth stack","\u002Fcomposables\u002Frecipes","3.composables\u002F3.recipes","i-lucide-book-marked",{"title":138,"path":139,"stem":140,"icon":141},"Composition","\u002Fcomposables\u002Fcomposition","3.composables\u002F4.composition","i-lucide-table","i-lucide-blocks",{"title":144,"icon":145,"path":146,"stem":147,"children":148,"page":218},"Reference","i-lucide-book-open","\u002Fmodules","4.modules",[149,154,158,163,168,173,177,182,186,191,195,200,205,209,213],{"title":150,"path":151,"stem":152,"icon":153},"Endpoint reference","\u002Fmodules\u002Fendpoints","4.modules\u002F01.endpoints","i-lucide-route",{"title":155,"path":156,"stem":157,"icon":78},"Identity management module","\u002Fmodules\u002Fidentity-management","4.modules\u002F02.identity-management",{"title":159,"path":160,"stem":161,"icon":162},"Cookie sign-in module","\u002Fmodules\u002Fcookie-auth","4.modules\u002F03.cookie-auth","i-lucide-cookie",{"title":164,"path":165,"stem":166,"icon":167},"Identity bearer sign-in module","\u002Fmodules\u002Fbearer-auth","4.modules\u002F04.bearer-auth","i-lucide-key",{"title":169,"path":170,"stem":171,"icon":172},"JWT module","\u002Fmodules\u002Fjwt","4.modules\u002F05.jwt","i-lucide-fingerprint",{"title":174,"path":175,"stem":176,"icon":83},"Passkeys module","\u002Fmodules\u002Fpasskeys","4.modules\u002F06.passkeys",{"title":178,"path":179,"stem":180,"icon":181},"ReAuth module","\u002Fmodules\u002Freauth","4.modules\u002F07.reauth","i-lucide-shield-alert",{"title":183,"path":184,"stem":185,"icon":59},"External OAuth packages","\u002Fmodules\u002Fexternal-oauth","4.modules\u002F08.external-oauth",{"title":187,"path":188,"stem":189,"icon":190},"Configuration options","\u002Fmodules\u002Fconfiguration","4.modules\u002F09.configuration","i-lucide-settings",{"title":192,"path":193,"stem":194,"icon":93},"Antiforgery (CSRF) rules","\u002Fmodules\u002Fcsrf","4.modules\u002F10.csrf",{"title":196,"path":197,"stem":198,"icon":199},"Responses and errors","\u002Fmodules\u002Ferrors","4.modules\u002F11.errors","i-lucide-circle-alert",{"title":201,"path":202,"stem":203,"icon":204},"Rate-limit policies","\u002Fmodules\u002Frate-limits","4.modules\u002F12.rate-limits","i-lucide-gauge",{"title":206,"path":207,"stem":208,"icon":108},"Email-code module","\u002Fmodules\u002Femail-code","4.modules\u002F13.email-code",{"title":210,"path":211,"stem":212,"icon":59},"Sign-in completer","\u002Fmodules\u002Fsign-in-completer","4.modules\u002F14.sign-in-completer",{"title":214,"path":215,"stem":216,"icon":217},"Enumeration-safe responses","\u002Fmodules\u002Fenumeration","4.modules\u002F15.enumeration","i-lucide-eye-off",false,{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":218},"Concepts","i-lucide-lightbulb","\u002Fconcepts","5.concepts",[225,230,235,240,245],{"title":226,"path":227,"stem":228,"icon":229},"AuthEndpoints compared with other options","\u002Fconcepts\u002Fcompare","5.concepts\u002F1.compare","i-lucide-git-compare",{"title":231,"path":232,"stem":233,"icon":234},"Stock Identity endpoints vs AuthEndpoints","\u002Fconcepts\u002Fstock-identity-vs-authendpoints","5.concepts\u002F2.stock-identity-vs-authendpoints","i-lucide-columns-2",{"title":236,"path":237,"stem":238,"icon":239},"MapIdentityApi alternative","\u002Fconcepts\u002Fmapidentityapi-alternative","5.concepts\u002F3.mapidentityapi-alternative","i-lucide-arrow-left-right",{"title":241,"path":242,"stem":243,"icon":244},"Security model","\u002Fconcepts\u002Fsecurity-model","5.concepts\u002F4.security-model","i-lucide-shield",{"title":246,"path":247,"stem":248,"icon":249},"FAQ","\u002Fconcepts\u002Ffaq","5.concepts\u002F5.faq","i-lucide-circle-help",{"id":251,"title":206,"body":252,"description":2015,"extension":2016,"faq":218,"links":2017,"meta":2018,"navigation":2019,"path":207,"seo":2020,"stem":208,"__hash__":2021},"docs\u002F4.modules\u002F13.email-code.md",{"type":253,"value":254,"toc":2003},"minimark",[255,269,274,359,403,414,463,493,502,506,538,552,580,620,624,630,698,707,711,721,777,793,813,835,839,844,925,937,1025,1040,1119,1128,1144,1147,1160,1377,1383,1438,1443,1550,1575,1590,1594,1676,1730,1734,1785,1797,1801,1810,1932,1956,1962,1966,1999],[256,257,258,259,263,264,268],"p",{},"Opt-in sign-in with a numeric code. ",[260,261,262],"code",{},"AllowSignUp"," and the magic link default to off. Steps for turning the feature on are in ",[265,266,105],"a",{"href":267},"\u002Fguides\u002Femail-code\u002F",".",[270,271,273],"h2",{"id":272},"di","DI",[275,276,281],"pre",{"className":277,"code":278,"language":279,"meta":280,"style":280},"language-cs shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","builder.Services.AddEmailCodeEndpoints\u003CAppUser, AppDbContext>(options =>\n{\n    options.CodeLength = 6;\n});\n","cs","",[260,282,283,326,332,353],{"__ignoreMap":280},[284,285,288,292,295,298,300,304,307,311,314,317,320,323],"span",{"class":286,"line":287},"line",1,[284,289,291],{"class":290},"sTEyZ","builder",[284,293,268],{"class":294},"sMK4o",[284,296,297],{"class":290},"Services",[284,299,268],{"class":294},[284,301,303],{"class":302},"s2Zo4","AddEmailCodeEndpoints",[284,305,306],{"class":294},"\u003C",[284,308,310],{"class":309},"sBMFI","AppUser",[284,312,313],{"class":294},",",[284,315,316],{"class":309}," AppDbContext",[284,318,319],{"class":294},">(",[284,321,322],{"class":309},"options",[284,324,325],{"class":294}," =>\n",[284,327,329],{"class":286,"line":328},2,[284,330,331],{"class":294},"{\n",[284,333,335,338,340,343,346,350],{"class":286,"line":334},3,[284,336,337],{"class":290},"    options",[284,339,268],{"class":294},[284,341,342],{"class":290},"CodeLength ",[284,344,345],{"class":294},"=",[284,347,349],{"class":348},"sbssI"," 6",[284,351,352],{"class":294},";\n",[284,354,356],{"class":286,"line":355},4,[284,357,358],{"class":294},"});\n",[256,360,361,363,364,367,368,371,372,375,376,379,380,383,384,387,388,391,392,395,396,399,400,402],{},[260,362,303],{}," registers the store, options validation, the ",[260,365,366],{},"AuthEndpoints.EmailCode.Send"," rate-limit policy, the ",[260,369,370],{},"AuthEndpoints.Login"," policy, the ",[260,373,374],{},"AuthEndpoints.ConfirmIdentity.EmailCode"," policy, and ",[260,377,378],{},"IdentityEmailCodeSignInCompleter\u003CTUser>"," (with ",[260,381,382],{},"TryAdd","). In Development it registers ",[260,385,386],{},"DevelopmentEmailCodeSender\u003CTUser>"," when no ",[260,389,390],{},"IEmailCodeSender\u003CTUser>"," is registered. It also registers ",[260,393,394],{},"TimeProvider.System"," and ",[260,397,398],{},"UpperInvariantLookupNormalizer"," with ",[260,401,382],{},", so an existing Identity normalizer and clock stay in place.",[256,404,405,406,409,410,413],{},"Finish verify in a built-in session by passing ",[260,407,408],{},"AuthEndpointsSession"," to the map. JWT needs ",[260,411,412],{},"AddJwtEndpoints"," first:",[275,415,417],{"className":277,"code":416,"language":279,"meta":280,"style":280},"app.MapGroup(\"\u002Fidentity\").MapEmailCodeEndpoints\u003CAppUser>(AuthEndpointsSession.Jwt);\n",[260,418,419],{"__ignoreMap":280},[284,420,421,424,426,429,432,435,439,441,444,447,449,451,453,455,457,460],{"class":286,"line":287},[284,422,423],{"class":290},"app",[284,425,268],{"class":294},[284,427,428],{"class":302},"MapGroup",[284,430,431],{"class":294},"(",[284,433,434],{"class":294},"\"",[284,436,438],{"class":437},"sfazB","\u002Fidentity",[284,440,434],{"class":294},[284,442,443],{"class":294},").",[284,445,446],{"class":302},"MapEmailCodeEndpoints",[284,448,306],{"class":294},[284,450,310],{"class":309},[284,452,319],{"class":294},[284,454,408],{"class":290},[284,456,268],{"class":294},[284,458,459],{"class":290},"Jwt",[284,461,462],{"class":294},");\n",[256,464,465,468,469,472,473,476,477,480,481,484,485,488,489,492],{},[260,466,467],{},"MapEmailCodeEndpoints\u003CTUser>()"," with no session keeps the 3.x completer. That is an explicitly registered ",[260,470,471],{},"IEmailCodeSignInCompleter\u003CTUser>",", otherwise Identity bearer. ",[260,474,475],{},"AddAuthEndpoints"," uses that parameterless map when ",[260,478,479],{},"EmailCode.Enabled"," is ",[260,482,483],{},"true",". That facade map ignores ",[260,486,487],{},"SignInCompletionOptions.Default",". ",[260,490,491],{},"Jwt.Enabled"," does not change it.",[256,494,495,498,499,268],{},[260,496,497],{},"AddEmailCodeSignInCompleter"," is obsolete. It still runs when the map passes no session. See ",[265,500,110],{"href":501},"\u002Fguides\u002Fupgrading-to-4\u002F",[270,503,505],{"id":504},"map","Map",[275,507,509],{"className":277,"code":508,"language":279,"meta":280,"style":280},"app.MapGroup(\"\u002Fidentity\").MapEmailCodeEndpoints\u003CAppUser>();\n",[260,510,511],{"__ignoreMap":280},[284,512,513,515,517,519,521,523,525,527,529,531,533,535],{"class":286,"line":287},[284,514,423],{"class":290},[284,516,268],{"class":294},[284,518,428],{"class":302},[284,520,431],{"class":294},[284,522,434],{"class":294},[284,524,438],{"class":437},[284,526,434],{"class":294},[284,528,443],{"class":294},[284,530,446],{"class":302},[284,532,306],{"class":294},[284,534,310],{"class":309},[284,536,537],{"class":294},">();\n",[256,539,540,541,544,545,547,548,480,550,268],{},"The facade maps this group under ",[260,542,543],{},"IdentityPath"," (default ",[260,546,438],{},") when ",[260,549,479],{},[260,551,483],{},[256,553,554,555,395,558,561,562,488,566,568,569,488,572,575,576,579],{},"Pair it with ",[260,556,557],{},"MapCookieSessionEndpoints",[260,559,560],{},"MapAccountManagementEndpoints"," when the prefix should skip password register and login. That host is ",[265,563,565],{"href":564},"\u002Fcomposables\u002Frecipes\u002F#email-code-only","Email-code only",[260,567,560],{}," then also maps ",[260,570,571],{},"POST \u002FconfirmIdentity\u002FemailCode\u002Fsend",[260,573,574],{},"POST \u002FconfirmIdentity"," accepts ",[260,577,578],{},"{ \"emailCode\" }"," when step-up by email is available for that user.",[256,581,582,584,585,588,589,591,592,595,596,599,600,603,604,607,608,611,612,615,616,619],{},[260,583,446],{}," throws ",[260,586,587],{},"InvalidOperationException"," if ",[260,590,303],{}," was not called. It throws ",[260,593,594],{},"NotSupportedException"," if the ",[260,597,598],{},"DbContext"," model has no ",[260,601,602],{},"EmailCodeEntry",". Call ",[260,605,606],{},"modelBuilder.UseEmailCodes()"," from ",[260,609,610],{},"OnModelCreating"," and migrate. The table is ",[260,613,614],{},"AuthEndpoints.AuthEndpointsEmailCodes",". It is not created unless ",[260,617,618],{},"UseEmailCodes()"," is called.",[270,621,623],{"id":622},"routes","Routes",[256,625,626,627,629],{},"Relative to the group prefix (facade default ",[260,628,438],{},"):",[631,632,633,655],"table",{},[634,635,636],"thead",{},[637,638,639,643,646,649,652],"tr",{},[640,641,642],"th",{},"Method",[640,644,645],{},"Path",[640,647,648],{},"Auth",[640,650,651],{},"CSRF",[640,653,654],{},"Rate limit",[656,657,658,679],"tbody",{},[637,659,660,666,671,673,675],{},[661,662,663],"td",{},[260,664,665],{},"POST",[661,667,668],{},[260,669,670],{},"\u002FemailCode\u002Fsend",[661,672],{},[661,674],{},[661,676,677],{},[260,678,366],{},[637,680,681,685,690,692,694],{},[661,682,683],{},[260,684,665],{},[661,686,687],{},[260,688,689],{},"\u002FemailCode\u002Fverify",[661,691],{},[661,693],{},[661,695,696],{},[260,697,370],{},[256,699,700,703,704,268],{},[260,701,702],{},"GET \u002FemailCode\u002Fverify"," is not mapped, so it returns ",[260,705,706],{},"405",[270,708,710],{"id":709},"send","Send",[256,712,713,714,717,718,268],{},"Request: ",[260,715,716],{},"EmailCodeSendRequest",", JSON ",[260,719,720],{},"{ \"email\" }",[631,722,723,733],{},[634,724,725],{},[637,726,727,730],{},[640,728,729],{},"Status",[640,731,732],{},"Body",[656,734,735,751,767],{},[637,736,737,742],{},[661,738,739],{},[260,740,741],{},"200",[661,743,744,747,748],{},[260,745,746],{},"EmailCodeSendResponse",": ",[260,749,750],{},"{ \"expiresInSeconds\", \"resendAfterSeconds\" }",[637,752,753,758],{},[661,754,755],{},[260,756,757],{},"400",[661,759,760,763,764],{},[260,761,762],{},"ValidationProblem"," with Identity code ",[260,765,766],{},"InvalidEmail",[637,768,769,774],{},[661,770,771],{},[260,772,773],{},"429",[661,775,776],{},"Empty. The per-IP send limit rejected the request",[256,778,779,480,782,785,786,480,789,792],{},[260,780,781],{},"expiresInSeconds",[260,783,784],{},"CodeLifetime"," in whole seconds. ",[260,787,788],{},"resendAfterSeconds",[260,790,791],{},"ResendCooldown"," in whole seconds.",[256,794,795,796,798,799,802,803,806,807,810,811,268],{},"The ",[260,797,741],{}," body is the same when the address is unknown, the user is locked out, the user is ineligible under ",[260,800,801],{},"UnconfirmedAccounts",", the resend cooldown applies, ",[260,804,805],{},"MaxSendsPerEmail"," is reached, or ",[260,808,809],{},"SendSignInCodeAsync"," throws for a reason other than the request being cancelled. A cancelled request is not turned into ",[260,812,741],{},[256,814,815,816,819,820,823,824,827,828,831,832,834],{},"Issuing the row runs inside ",[260,817,818],{},"Database.CreateExecutionStrategy()",", so a context that uses ",[260,821,822],{},"EnableRetryOnFailure"," can send. A SQL Server deadlock (error 1205), a MySQL deadlock (error 1213), a Postgres serialization failure (",[260,825,826],{},"40001",") or deadlock (",[260,829,830],{},"40P01","), or a SQLite busy or locked error (5 or 6) is a conflict. The store tries that insert twice. When the store call throws the same conflict, send tries the call twice. That is up to four attempts. A provider execution strategy can retry inside each attempt. If the conflict remains, send returns the same ",[260,833,741],{}," and does not send mail.",[270,836,838],{"id":837},"verify","Verify",[256,840,713,841,268],{},[260,842,843],{},"EmailCodeVerifyRequest",[631,845,846,856],{},[634,847,848],{},[637,849,850,853],{},[640,851,852],{},"Field",[640,854,855],{},"Role",[656,857,858,870,885,901,911],{},[637,859,860,865],{},[661,861,862],{},[260,863,864],{},"email",[661,866,867,868],{},"Required with ",[260,869,260],{},[637,871,872,876],{},[661,873,874],{},[260,875,260],{},[661,877,867,878,880,881,884],{},[260,879,864],{},". Length must equal ",[260,882,883],{},"CodeLength",", and every character must be a digit",[637,886,887,892],{},[661,888,889],{},[260,890,891],{},"token",[661,893,894,895,897,898,900],{},"Required alone when the magic link is on. Do not send ",[260,896,864],{}," or ",[260,899,260],{}," with it",[637,902,903,908],{},[661,904,905],{},[260,906,907],{},"twoFactorCode",[661,909,910],{},"TOTP, when the user has two-factor authentication on",[637,912,913,918],{},[661,914,915],{},[260,916,917],{},"twoFactorRecoveryCode",[661,919,920,921,924],{},"Recovery code. Redeemed after the row is consumed. A failed redeem clears ",[260,922,923],{},"ConsumedAt"," and leaves the attempt",[256,926,927,928,395,931,934,935,268],{},"Query ",[260,929,930],{},"useCookies",[260,932,933],{},"useSessionCookies"," are passed to the completer named by ",[260,936,446],{},[631,938,939,954],{},[634,940,941],{},[637,942,943,946,951],{},[640,944,945],{},"Session",[640,947,948,950],{},[260,949,741],{}," body",[640,952,953],{},"Flags",[656,955,956,977,1006],{},[637,957,958,963,966],{},[661,959,960],{},[260,961,962],{},"Cookie",[661,964,965],{},"Empty. The application cookie is set.",[661,967,968,969,480,971,488,974,976],{},"Persistent only when ",[260,970,933],{},[260,972,973],{},"false",[260,975,930],{}," is ignored. Omit the flag for a session cookie.",[637,978,979,984,987],{},[661,980,981],{},[260,982,983],{},"IdentityBearer",[661,985,986],{},"Identity bearer token JSON when neither flag is set. Empty when a cookie is set.",[661,988,989,990,897,992,480,994,996,997,480,999,395,1001,1003,1004,268],{},"A cookie only when ",[260,991,930],{},[260,993,933],{},[260,995,483],{},". Persistent only when ",[260,998,930],{},[260,1000,483],{},[260,1002,933],{}," is not ",[260,1005,483],{},[637,1007,1008,1012,1022],{},[661,1009,1010],{},[260,1011,459],{},[661,1013,1014,1017,1018,1021],{},[260,1015,1016],{},"{ \"accessToken\", \"tokenType\": \"Bearer\" }"," and the ",[260,1019,1020],{},"AuthEndpoints.Jwt.RefreshToken"," cookie.",[661,1023,1024],{},"Both flags are ignored.",[256,1026,1027,1028,1030,1031,1033,1034,1030,1037,1039],{},"An explicitly registered 3.x completer follows its own rules when the map passes no session. ",[260,1029,378],{}," matches the ",[260,1032,983],{}," row. ",[260,1035,1036],{},"JwtEmailCodeSignInCompleter\u003CTUser>",[260,1038,459],{}," row.",[631,1041,1042,1050],{},[634,1043,1044],{},[637,1045,1046,1048],{},[640,1047,729],{},[640,1049,732],{},[656,1051,1052,1061,1079,1096,1110],{},[637,1053,1054,1058],{},[661,1055,1056],{},[260,1057,741],{},[661,1059,1060],{},"Empty when the result is an application cookie. Otherwise the completer's token JSON",[637,1062,1063,1067],{},[661,1064,1065],{},[260,1066,757],{},[661,1068,1069,1071,1072,1075,1076],{},[260,1070,762],{}," ",[260,1073,1074],{},"InvalidEmailCodeRequest",", description ",[260,1077,1078],{},"Provide an email and a numeric code.",[637,1080,1081,1086],{},[661,1082,1083],{},[260,1084,1085],{},"401",[661,1087,1088,1089,1092,1093],{},"Problem details, title ",[260,1090,1091],{},"Unauthorized",", detail ",[260,1094,1095],{},"Invalid or expired code.",[637,1097,1098,1102],{},[661,1099,1100],{},[260,1101,1085],{},[661,1103,1088,1104,1092,1107],{},[260,1105,1106],{},"RequiresTwoFactor",[260,1108,1109],{},"Two-factor authentication is required.",[637,1111,1112,1116],{},[661,1113,1114],{},[260,1115,773],{},[661,1117,1118],{},"Empty. The login rate limit rejected the request",[256,1120,1121,1123,1124,1127],{},[260,1122,1095],{}," covers a wrong code, a wrong token, an expired or consumed row, an attempt cap, a lockout, a failed second factor, a failed sign-up, a failed credential reset, and ",[260,1125,1126],{},"CanSignInAsync"," returning false.",[256,1129,1130,1132,1133,480,1136,395,1138,480,1141,1143],{},[260,1131,1106],{}," is returned only when ",[260,1134,1135],{},"RequireTwoFactor",[260,1137,483],{},[260,1139,1140],{},"GetTwoFactorEnabledAsync",[260,1142,483],{},", and the body has neither second-factor field. That response releases the reserved attempt, so the same code can be sent again with a factor. A wrong factor keeps the attempt.",[270,1145,1146],{"id":322},"Options",[256,1148,1149,1152,1153,1156,1157,1159],{},[260,1150,1151],{},"EmailCodeOptions",", set from ",[260,1154,1155],{},"AuthEndpointsEmailCodeOptions.Configure"," or the ",[260,1158,303],{}," callback:",[631,1161,1162,1175],{},[634,1163,1164],{},[637,1165,1166,1169,1172],{},[640,1167,1168],{},"Property",[640,1170,1171],{},"Default",[640,1173,1174],{},"Validation",[656,1176,1177,1191,1203,1218,1230,1243,1256,1270,1286,1301,1318,1336,1352,1365],{},[637,1178,1179,1183,1188],{},[661,1180,1181],{},[260,1182,883],{},[661,1184,1185],{},[260,1186,1187],{},"6",[661,1189,1190],{},"6 through 10",[637,1192,1193,1197,1200],{},[661,1194,1195],{},[260,1196,784],{},[661,1198,1199],{},"10 minutes",[661,1201,1202],{},"1 minute through 60 minutes",[637,1204,1205,1210,1215],{},[661,1206,1207],{},[260,1208,1209],{},"MaxAttempts",[661,1211,1212],{},[260,1213,1214],{},"5",[661,1216,1217],{},"1 through 10",[637,1219,1220,1224,1227],{},[661,1221,1222],{},[260,1223,791],{},[661,1225,1226],{},"60 seconds",[661,1228,1229],{},"0 through 10 minutes",[637,1231,1232,1236,1240],{},[661,1233,1234],{},[260,1235,805],{},[661,1237,1238],{},[260,1239,1214],{},[661,1241,1242],{},"At least 1",[637,1244,1245,1250,1253],{},[661,1246,1247],{},[260,1248,1249],{},"SendWindow",[661,1251,1252],{},"1 hour",[661,1254,1255],{},"Greater than zero",[637,1257,1258,1263,1267],{},[661,1259,1260],{},[260,1261,1262],{},"SendsPerIpPerMinute",[661,1264,1265],{},[260,1266,1214],{},[661,1268,1269],{},"At least 1. This is the fixed-window IP limit",[637,1271,1272,1276,1280],{},[661,1273,1274],{},[260,1275,262],{},[661,1277,1278],{},[260,1279,973],{},[661,1281,1282,1283,1285],{},"When ",[260,1284,483],{},", an unknown address can receive a code that creates a user",[637,1287,1288,1292,1296],{},[661,1289,1290],{},[260,1291,1135],{},[661,1293,1294],{},[260,1295,483],{},[661,1297,1282,1298,1300],{},[260,1299,483],{},", a user with two-factor authentication on must present a TOTP or recovery code",[637,1302,1303,1307,1312],{},[661,1304,1305],{},[260,1306,801],{},[661,1308,1309],{},[260,1310,1311],{},"ConfirmAndResetCredentials",[661,1313,1314,1317],{},[260,1315,1316],{},"Reject"," refuses an unconfirmed account that already has a password, external login, or passkey",[637,1319,1320,1325,1329],{},[661,1321,1322],{},[260,1323,1324],{},"CountFailuresTowardLockout",[661,1326,1327],{},[260,1328,483],{},[661,1330,1331,1332,1335],{},"A wrong code or wrong second factor calls ",[260,1333,1334],{},"AccessFailedAsync"," when a user exists",[637,1337,1338,1343,1347],{},[661,1339,1340],{},[260,1341,1342],{},"RequireSenderOutsideDevelopment",[661,1344,1345],{},[260,1346,483],{},[661,1348,1349,1350],{},"Outside Development, startup fails without a real ",[260,1351,390],{},[637,1353,1354,1359,1362],{},[661,1355,1356],{},[260,1357,1358],{},"ReAuth",[661,1360,1361],{},"enabled, 5 minutes",[661,1363,1364],{},"See below",[637,1366,1367,1372,1375],{},[661,1368,1369],{},[260,1370,1371],{},"MagicLink",[661,1373,1374],{},"disabled",[661,1376,1364],{},[256,1378,1379,1382],{},[260,1380,1381],{},"EmailCodeReAuthOptions",":",[631,1384,1385,1396],{},[634,1386,1387],{},[637,1388,1389,1391,1393],{},[640,1390,1168],{},[640,1392,1171],{},[640,1394,1395],{},"Notes",[656,1397,1398,1423],{},[637,1399,1400,1405,1409],{},[661,1401,1402],{},[260,1403,1404],{},"Enabled",[661,1406,1407],{},[260,1408,483],{},[661,1410,1282,1411,1413,1414,1417,1418,1071,1420],{},[260,1412,973],{},", ",[260,1415,1416],{},"authMethods.emailCode"," is false and send returns ",[260,1419,757],{},[260,1421,1422],{},"EmailCodeProofUnavailable",[637,1424,1425,1429,1432],{},[661,1426,1427],{},[260,1428,784],{},[661,1430,1431],{},"5 minutes",[661,1433,1434,1435,1437],{},"1 minute through 10 minutes. Sign-in codes keep ",[260,1436,784],{}," (default 10 minutes). The proof is offered only when the user has no password, no authenticator, and no passkey. An external login is not a stronger factor",[256,1439,1440,1382],{},[260,1441,1442],{},"EmailCodeMagicLinkOptions",[631,1444,1445,1455],{},[634,1446,1447],{},[637,1448,1449,1451,1453],{},[640,1450,1168],{},[640,1452,1171],{},[640,1454,1395],{},[656,1456,1457,1477,1513,1526],{},[637,1458,1459,1463,1467],{},[661,1460,1461],{},[260,1462,1404],{},[661,1464,1465],{},[260,1466,973],{},[661,1468,1282,1469,1471,1472,1474,1475],{},[260,1470,973],{},", any ",[260,1473,891],{}," in the verify body is ",[260,1476,757],{},[637,1478,1479,1484,1489],{},[661,1480,1481],{},[260,1482,1483],{},"LinkUri",[661,1485,1486],{},[260,1487,1488],{},"null",[661,1490,1491,1492,480,1494,1496,1497,1500,1501,1504,1505,1508,1509,1512],{},"Required when ",[260,1493,1404],{},[260,1495,483],{},". An absolute ",[260,1498,1499],{},"http(s)"," URI with no ",[260,1502,1503],{},"#",". A rooted path such as ",[260,1506,1507],{},"\u002Fauth\u002Femail-link"," is accepted when ",[260,1510,1511],{},"BuildLinkUrl"," is set",[637,1514,1515,1520,1523],{},[661,1516,1517],{},[260,1518,1519],{},"AllowedOrigins",[661,1521,1522],{},"empty",[661,1524,1525],{},"Required in Production. Each entry is an origin",[637,1527,1528,1532,1536],{},[661,1529,1530],{},[260,1531,1511],{},[661,1533,1534],{},[260,1535,1488],{},[661,1537,1538,1541,1542,1413,1544,480,1547],{},[260,1539,1540],{},"Func\u003CEmailCodeLinkContext, string>",". When ",[260,1543,1488],{},[260,1545,1546],{},"LinkUrl",[260,1548,1549],{},"LinkUri + \"#token=\" + token",[256,1551,1552,1553,1555,1556,1558,1559,1561,1562,1564,1565,1568,1569,1571,1572,1574],{},"Startup rejects a missing ",[260,1554,1483],{},", a relative path, a ",[260,1557,1483],{}," that contains ",[260,1560,1503],{},", a protocol-relative URI, and a non-http(s) scheme. A rooted path is rejected unless ",[260,1563,1511],{}," is set. An absolute URI still has to use ",[260,1566,1567],{},"https"," in Production, and its origin has to be in ",[260,1570,1519],{},", including when ",[260,1573,1511],{}," is set.",[256,1576,1577,1578,1581,1582,488,1584,480,1587,268],{},"Facade flag ",[260,1579,1580],{},"AuthEndpointsEmailCodeOptions.Enabled"," defaults to ",[260,1583,973],{},[260,1585,1586],{},"Configure",[260,1588,1589],{},"Action\u003CEmailCodeOptions>",[270,1591,1593],{"id":1592},"sender","Sender",[275,1595,1597],{"className":277,"code":1596,"language":279,"meta":280,"style":280},"public interface IEmailCodeSender\u003CTUser> where TUser : class\n{\n    Task SendSignInCodeAsync(EmailCodeMessage\u003CTUser> message, CancellationToken cancellationToken = default);\n}\n",[260,1598,1599,1631,1635,1671],{"__ignoreMap":280},[284,1600,1601,1605,1608,1611,1613,1616,1619,1622,1625,1628],{"class":286,"line":287},[284,1602,1604],{"class":1603},"spNyl","public",[284,1606,1607],{"class":309}," interface",[284,1609,1610],{"class":309}," IEmailCodeSender",[284,1612,306],{"class":294},[284,1614,1615],{"class":309},"TUser",[284,1617,1618],{"class":294},">",[284,1620,1621],{"class":1603}," where",[284,1623,1624],{"class":309}," TUser",[284,1626,1627],{"class":294}," :",[284,1629,1630],{"class":309}," class\n",[284,1632,1633],{"class":286,"line":328},[284,1634,331],{"class":294},[284,1636,1637,1640,1643,1645,1648,1650,1652,1654,1657,1659,1662,1665,1668],{"class":286,"line":334},[284,1638,1639],{"class":309},"    Task",[284,1641,1642],{"class":302}," SendSignInCodeAsync",[284,1644,431],{"class":294},[284,1646,1647],{"class":309},"EmailCodeMessage",[284,1649,306],{"class":294},[284,1651,1615],{"class":309},[284,1653,1618],{"class":294},[284,1655,1656],{"class":309}," message",[284,1658,313],{"class":294},[284,1660,1661],{"class":309}," CancellationToken",[284,1663,1664],{"class":309}," cancellationToken",[284,1666,1667],{"class":294}," =",[284,1669,1670],{"class":294}," default);\n",[284,1672,1673],{"class":286,"line":355},[284,1674,1675],{"class":294},"}\n",[256,1677,1678,480,1681,1684,1685,1688,1689,1684,1692,1695,1696,1684,1698,1701,1702,395,1705,1707,1708,1710,1711,1713,1714,1717,1718,1720,1721,1724,1725,488,1727,1729],{},[260,1679,1680],{},"EmailCodePurpose",[260,1682,1683],{},"SignIn"," (",[260,1686,1687],{},"0","), ",[260,1690,1691],{},"SignUp",[260,1693,1694],{},"1","), or ",[260,1697,1358],{},[260,1699,1700],{},"2","). ",[260,1703,1704],{},"Code",[260,1706,1546],{}," are raw. Encode them when the template is HTML. ",[260,1709,1358],{}," is a step-up message (\"confirm it's you\"), not a sign-in, and ",[260,1712,1546],{}," is null. ",[260,1715,1716],{},"POST \u002FemailCode\u002Fsend"," awaits ",[260,1719,809],{},", so queue the message and return. The library log category is ",[260,1722,1723],{},"AuthEndpoints.EmailCode",". Those logs include a user id and an email-hash prefix. They do not include the address, the code, the token, or ",[260,1726,1546],{},[260,1728,386],{}," logs the raw code at warning. Do not register it outside Development.",[270,1731,1733],{"id":1732},"sign-up-and-unconfirmed-accounts","Sign-up and unconfirmed accounts",[256,1735,1736,1737,1071,1739,1741,1742,399,1744,395,1747,1750,1751,1754,1755,1757,1758,1761,1762,1754,1765,1767,1768,1771,1772,1775,1776,1754,1779,1781,1782,1784],{},"With ",[260,1738,262],{},[260,1740,483],{},", verify of a correct code for an unknown address creates ",[260,1743,1615],{},[260,1745,1746],{},"UserName",[260,1748,1749],{},"Email"," set to the trimmed address, sets ",[260,1752,1753],{},"EmailConfirmed"," to ",[260,1756,483],{}," before ",[260,1759,1760],{},"CreateAsync",", and sets ",[260,1763,1764],{},"EmailCodeSignInContext.IsNewUser",[260,1766,483],{},". It does not use the email-confirmation token provider, does not set a password, and does not call ",[260,1769,1770],{},"IEmailSender\u003CTUser>",". A duplicate create, including a ",[260,1773,1774],{},"DbUpdateException"," from a concurrent register, uses the user that already has that email and sets ",[260,1777,1778],{},"IsNewUser",[260,1780,973],{},". When that user is already confirmed, the password stays in place. If the lookup finds no user, verify returns ",[260,1783,1085],{},". A duplicate sign-up that still needs two-factor authentication releases the reserved attempt and does not consume the code.",[256,1786,1787,1789,1790,1793,1794,1796],{},[260,1788,1311],{}," removes the password, each external login, and each passkey, then calls ",[260,1791,1792],{},"UpdateSecurityStampAsync",", and only then confirms the email. If any removal or the stamp update fails, verify returns ",[260,1795,1085],{}," and does not confirm the email.",[270,1798,1800],{"id":1799},"storage","Storage",[256,1802,1803,1805,1806,1754,1808,268],{},[260,1804,618],{}," maps ",[260,1807,602],{},[260,1809,614],{},[631,1811,1812,1822],{},[634,1813,1814],{},[637,1815,1816,1819],{},[640,1817,1818],{},"Column",[640,1820,1821],{},"Contents",[656,1823,1824,1842,1855,1868,1881,1894,1907,1917],{},[637,1825,1826,1831],{},[661,1827,1828],{},[260,1829,1830],{},"Purpose",[661,1832,1833,1835,1836,1838,1839,1841],{},[260,1834,1687],{}," sign-in (including sign-up messages) or ",[260,1837,1694],{}," step-up. Default ",[260,1840,1687],{},", so existing rows stay sign-in",[637,1843,1844,1849],{},[661,1845,1846],{},[260,1847,1848],{},"EmailHash",[661,1850,1851,1852],{},"SHA-256 hex of the address after trim and ",[260,1853,1854],{},"ILookupNormalizer.NormalizeEmail",[637,1856,1857,1862],{},[661,1858,1859],{},[260,1860,1861],{},"CodeHash",[661,1863,1864,1865],{},"SHA-256 hex of ",[260,1866,1867],{},"Id + \":\" + code",[637,1869,1870,1875],{},[661,1871,1872],{},[260,1873,1874],{},"LinkTokenHash",[661,1876,1877,1878,1880],{},"SHA-256 hex of the token, or ",[260,1879,1488],{}," when the magic link is off",[637,1882,1883,1888],{},[661,1884,1885],{},[260,1886,1887],{},"SignupEmail",[661,1889,1890,1891,1893],{},"The trimmed address for a sign-up row, so a token-only verify can create the user. ",[260,1892,1488],{}," on every other row",[637,1895,1896,1904],{},[661,1897,1898,1413,1901],{},[260,1899,1900],{},"UserId",[260,1902,1903],{},"SecurityStamp",[661,1905,1906],{},"Set for an eligible existing user. A later stamp or email change makes the row fail verify",[637,1908,1909,1914],{},[661,1910,1911],{},[260,1912,1913],{},"Attempts",[661,1915,1916],{},"Incremented by a conditional update before the code is compared",[637,1918,1919,1929],{},[661,1920,1921,1413,1923,1413,1926],{},[260,1922,923],{},[260,1924,1925],{},"SupersededAt",[260,1927,1928],{},"ExpiresAt",[661,1930,1931],{},"Consume, replace, and expiry marks",[256,1933,1934,1935,1937,1938,1941,1942,1945,1946,395,1948,1950,1951,897,1953,1955],{},"The code compare uses a fixed-time equality check. The unique index on ",[260,1936,1874],{}," has no filter. The non-unique index is ",[260,1939,1940],{},"(EmailHash, Purpose, CreatedAt)",", named ",[260,1943,1944],{},"IX_AuthEndpointsEmailCodes_EmailHash_Purpose_CreatedAt",". Cooldown, the per-address send cap, supersede, and retention of expired rows are limited to that purpose. A step-up row stores ",[260,1947,1900],{},[260,1949,1903],{},", and it never stores ",[260,1952,1874],{},[260,1954,1887],{},". Sign-in verify ignores step-up rows, including by link token.",[256,1957,1958,1959,268],{},"Expiry, cooldown, and the send cap use ",[260,1960,1961],{},"TimeProvider",[270,1963,1965],{"id":1964},"related","Related",[1967,1968,1969,1974,1979,1984,1989,1994],"ul",{},[1970,1971,1972],"li",{},[265,1973,105],{"href":267},[1970,1975,1976],{},[265,1977,150],{"href":1978},"\u002Fmodules\u002Fendpoints\u002F",[1970,1980,1981],{},[265,1982,187],{"href":1983},"\u002Fmodules\u002Fconfiguration\u002F",[1970,1985,1986],{},[265,1987,196],{"href":1988},"\u002Fmodules\u002Ferrors\u002F",[1970,1990,1991],{},[265,1992,201],{"href":1993},"\u002Fmodules\u002Frate-limits\u002F",[1970,1995,1996],{},[265,1997,192],{"href":1998},"\u002Fmodules\u002Fcsrf\u002F",[2000,2001,2002],"style",{},"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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":280,"searchDepth":287,"depth":328,"links":2004},[2005,2006,2007,2008,2009,2010,2011,2012,2013,2014],{"id":272,"depth":328,"text":273},{"id":504,"depth":328,"text":505},{"id":622,"depth":328,"text":623},{"id":709,"depth":328,"text":710},{"id":837,"depth":328,"text":838},{"id":322,"depth":328,"text":1146},{"id":1592,"depth":328,"text":1593},{"id":1732,"depth":328,"text":1733},{"id":1799,"depth":328,"text":1800},{"id":1964,"depth":328,"text":1965},"Reference for emailed one-time codes, optional sign-up, and optional magic links.","md",null,{},{"icon":108},{"title":206,"description":2015},"JPCHdnmHD4ELznrTz5zoWxjCKdS-QqXPB4QgAonCmd4",[2023,2025],{"title":201,"path":202,"stem":203,"description":2024,"icon":204,"children":-1},"The rate-limit policies AuthEndpoints registers, their limits, and the routes that use them.",{"title":210,"path":211,"stem":212,"description":2026,"icon":59,"children":-1},"The session a successful sign-in finishes in, and how to replace that step.",1792054259113]