[{"data":1,"prerenderedAt":716},["ShallowReactive",2],{"navigation":3,"\u002Fmodules\u002Fopeniddict":223,"\u002Fmodules\u002Fopeniddict-surround":711},[4,43,110,118,197],{"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":109},"Guides","i-lucide-waypoints","\u002Fguides","2.guides",[49,54,59,64,69,74,79,84,89,94,99,104],{"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",{"title":105,"path":106,"stem":107,"icon":108},"List and revoke signed-in sessions","\u002Fguides\u002Factive-sessions","2.guides\u002F13.active-sessions","i-lucide-monitor-smartphone",false,{"title":111,"path":112,"stem":113,"children":114,"icon":117},"Composables","\u002Fcomposables","3.composables\u002F1.index",[115],{"title":116,"path":112,"stem":113,"icon":117},"Build a custom stack","i-lucide-blocks",{"title":119,"icon":120,"path":121,"stem":122,"children":123,"page":109},"Reference","i-lucide-book-open","\u002Fmodules","4.modules",[124,129,133,138,142,147,152,157,161,166,170,175,179,184,189,193],{"title":125,"path":126,"stem":127,"icon":128},"Endpoint reference","\u002Fmodules\u002Fendpoints","4.modules\u002F01.endpoints","i-lucide-route",{"title":130,"path":131,"stem":132,"icon":78},"Password auth","\u002Fmodules\u002Fpassword-auth","4.modules\u002F02.password-auth",{"title":134,"path":135,"stem":136,"icon":137},"Composition table","\u002Fmodules\u002Fcomposition","4.modules\u002F03.composition","i-lucide-table",{"title":139,"path":140,"stem":141,"icon":83},"Identity module","\u002Fmodules\u002Fidentity-management","4.modules\u002F04.identity-management",{"title":143,"path":144,"stem":145,"icon":146},"Cookie sign-in","\u002Fmodules\u002Fcookie-auth","4.modules\u002F05.cookie-auth","i-lucide-cookie",{"title":148,"path":149,"stem":150,"icon":151},"Identity bearer","\u002Fmodules\u002Fbearer-auth","4.modules\u002F06.bearer-auth","i-lucide-key",{"title":153,"path":154,"stem":155,"icon":156},"JWT","\u002Fmodules\u002Fjwt","4.modules\u002F07.jwt","i-lucide-fingerprint",{"title":158,"path":159,"stem":160,"icon":88},"Passkeys","\u002Fmodules\u002Fpasskeys","4.modules\u002F08.passkeys",{"title":162,"path":163,"stem":164,"icon":165},"Step-up ReAuth","\u002Fmodules\u002Freauth","4.modules\u002F09.reauth","i-lucide-shield-alert",{"title":167,"path":168,"stem":169,"icon":58},"External OAuth","\u002Fmodules\u002Fexternal-oauth","4.modules\u002F10.external-oauth",{"title":171,"path":172,"stem":173,"icon":174},"Configuration","\u002Fmodules\u002Fconfiguration","4.modules\u002F11.configuration","i-lucide-settings",{"title":176,"path":177,"stem":178,"icon":98},"CSRF rules","\u002Fmodules\u002Fcsrf","4.modules\u002F12.csrf",{"title":180,"path":181,"stem":182,"icon":183},"Responses","\u002Fmodules\u002Ferrors","4.modules\u002F13.errors","i-lucide-circle-alert",{"title":185,"path":186,"stem":187,"icon":188},"Rate-limit policies","\u002Fmodules\u002Frate-limits","4.modules\u002F14.rate-limits","i-lucide-gauge",{"title":190,"path":191,"stem":192,"icon":73},"Email codes","\u002Fmodules\u002Femail-code","4.modules\u002F15.email-code",{"title":194,"path":195,"stem":196,"icon":78},"OAuth server","\u002Fmodules\u002Fopeniddict","4.modules\u002F16.openiddict",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":109},"Concepts","i-lucide-lightbulb","\u002Fconcepts","5.concepts",[203,208,213,218],{"title":204,"path":205,"stem":206,"icon":207},"Comparison","\u002Fconcepts\u002Fcompare","5.concepts\u002F1.compare","i-lucide-git-compare",{"title":209,"path":210,"stem":211,"icon":212},"Security model","\u002Fconcepts\u002Fsecurity-model","5.concepts\u002F2.security-model","i-lucide-shield",{"title":214,"path":215,"stem":216,"icon":217},"Production","\u002Fconcepts\u002Fproduction","5.concepts\u002F3.production","i-lucide-factory",{"title":219,"path":220,"stem":221,"icon":222},"FAQ","\u002Fconcepts\u002Ffaq","5.concepts\u002F4.faq","i-lucide-circle-help",{"id":224,"title":225,"body":226,"description":704,"extension":705,"faq":109,"links":706,"meta":707,"navigation":708,"path":195,"seo":709,"stem":196,"__hash__":710},"docs\u002F4.modules\u002F16.openiddict.md","OAuth server (OpenIddict)",{"type":227,"value":228,"toc":699},"minimark",[229,241,250,255,266,557,655,659,665,669,695],[230,231,232,236,237,240],"p",{},[233,234,235],"code",{},"AuthEndpoints.OpenIddict"," (preview) turns an AuthEndpoints app into an OAuth 2.0 authorization server, built on OpenIddict 7.7. The core ",[233,238,239],{},"AuthEndpoints"," package does not change and has no OpenIddict dependency.",[230,242,243,244,249],{},"The package ",[245,246,248],"a",{"href":247},"https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpoints\u002Ftree\u002Fmain\u002Fsrc\u002FAuthEndpoints.OpenIddict#readme","README"," covers setup, the consent step, certificates, dynamic registration, and every setting.",[251,252,254],"h2",{"id":253},"in-short","In short",[230,256,257,258,261,262,265],{},"The default recipe is one registration call and one map call, like ",[233,259,260],{},"AddPasswordAuth"," \u002F ",[233,263,264],{},"MapPasswordAuth",":",[267,268,273],"pre",{"className":269,"code":270,"language":271,"meta":272,"style":272},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","builder.Services.AddOAuthServer\u003CAppUser, AppDbContext>(options =>\n{\n    options.Issuer = new Uri(\"https:\u002F\u002Fauth.example.com\u002F\");\n    options.Audience = \"https:\u002F\u002Fapi.example.com\u002F\";\n    options.Scopes.Add(\"api\");\n    options.LoginUrl = \"https:\u002F\u002Fapp.example.com\u002Fsign-in\";\n    options.ConsentUrl = \"https:\u002F\u002Fapp.example.com\u002Foauth\u002Fconsent\";\n    options.Certificates.Path = \"\u002Fvar\u002Flib\u002Fmyapp\u002Foauth-keys\";\n});\n\n\u002F\u002F OnModelCreating\nbuilder.UseAuthEndpointsOpenIddict\u003CAppUser>();\n\napp.MapOAuthServer();\nawait app.Services.SeedOAuthClientsAsync(); \u002F\u002F after migrations, when options.Clients is used\n","csharp","",[233,274,275,319,325,360,383,409,430,451,477,483,490,497,514,519,533],{"__ignoreMap":272},[276,277,280,284,288,291,293,297,300,304,307,310,313,316],"span",{"class":278,"line":279},"line",1,[276,281,283],{"class":282},"sTEyZ","builder",[276,285,287],{"class":286},"sMK4o",".",[276,289,290],{"class":282},"Services",[276,292,287],{"class":286},[276,294,296],{"class":295},"s2Zo4","AddOAuthServer",[276,298,299],{"class":286},"\u003C",[276,301,303],{"class":302},"sBMFI","AppUser",[276,305,306],{"class":286},",",[276,308,309],{"class":302}," AppDbContext",[276,311,312],{"class":286},">(",[276,314,315],{"class":302},"options",[276,317,318],{"class":286}," =>\n",[276,320,322],{"class":278,"line":321},2,[276,323,324],{"class":286},"{\n",[276,326,328,331,333,336,339,342,345,348,351,355,357],{"class":278,"line":327},3,[276,329,330],{"class":282},"    options",[276,332,287],{"class":286},[276,334,335],{"class":282},"Issuer ",[276,337,338],{"class":286},"=",[276,340,341],{"class":286}," new",[276,343,344],{"class":302}," Uri",[276,346,347],{"class":286},"(",[276,349,350],{"class":286},"\"",[276,352,354],{"class":353},"sfazB","https:\u002F\u002Fauth.example.com\u002F",[276,356,350],{"class":286},[276,358,359],{"class":286},");\n",[276,361,363,365,367,370,372,375,378,380],{"class":278,"line":362},4,[276,364,330],{"class":282},[276,366,287],{"class":286},[276,368,369],{"class":282},"Audience ",[276,371,338],{"class":286},[276,373,374],{"class":286}," \"",[276,376,377],{"class":353},"https:\u002F\u002Fapi.example.com\u002F",[276,379,350],{"class":286},[276,381,382],{"class":286},";\n",[276,384,386,388,390,393,395,398,400,402,405,407],{"class":278,"line":385},5,[276,387,330],{"class":282},[276,389,287],{"class":286},[276,391,392],{"class":282},"Scopes",[276,394,287],{"class":286},[276,396,397],{"class":295},"Add",[276,399,347],{"class":286},[276,401,350],{"class":286},[276,403,404],{"class":353},"api",[276,406,350],{"class":286},[276,408,359],{"class":286},[276,410,412,414,416,419,421,423,426,428],{"class":278,"line":411},6,[276,413,330],{"class":282},[276,415,287],{"class":286},[276,417,418],{"class":282},"LoginUrl ",[276,420,338],{"class":286},[276,422,374],{"class":286},[276,424,425],{"class":353},"https:\u002F\u002Fapp.example.com\u002Fsign-in",[276,427,350],{"class":286},[276,429,382],{"class":286},[276,431,433,435,437,440,442,444,447,449],{"class":278,"line":432},7,[276,434,330],{"class":282},[276,436,287],{"class":286},[276,438,439],{"class":282},"ConsentUrl ",[276,441,338],{"class":286},[276,443,374],{"class":286},[276,445,446],{"class":353},"https:\u002F\u002Fapp.example.com\u002Foauth\u002Fconsent",[276,448,350],{"class":286},[276,450,382],{"class":286},[276,452,454,456,458,461,463,466,468,470,473,475],{"class":278,"line":453},8,[276,455,330],{"class":282},[276,457,287],{"class":286},[276,459,460],{"class":282},"Certificates",[276,462,287],{"class":286},[276,464,465],{"class":282},"Path ",[276,467,338],{"class":286},[276,469,374],{"class":286},[276,471,472],{"class":353},"\u002Fvar\u002Flib\u002Fmyapp\u002Foauth-keys",[276,474,350],{"class":286},[276,476,382],{"class":286},[276,478,480],{"class":278,"line":479},9,[276,481,482],{"class":286},"});\n",[276,484,486],{"class":278,"line":485},10,[276,487,489],{"emptyLinePlaceholder":488},true,"\n",[276,491,493],{"class":278,"line":492},11,[276,494,496],{"class":495},"sHwdD","\u002F\u002F OnModelCreating\n",[276,498,500,502,504,507,509,511],{"class":278,"line":499},12,[276,501,283],{"class":282},[276,503,287],{"class":286},[276,505,506],{"class":295},"UseAuthEndpointsOpenIddict",[276,508,299],{"class":286},[276,510,303],{"class":302},[276,512,513],{"class":286},">();\n",[276,515,517],{"class":278,"line":516},13,[276,518,489],{"emptyLinePlaceholder":488},[276,520,522,525,527,530],{"class":278,"line":521},14,[276,523,524],{"class":282},"app",[276,526,287],{"class":286},[276,528,529],{"class":295},"MapOAuthServer",[276,531,532],{"class":286},"();\n",[276,534,536,539,542,544,546,548,551,554],{"class":278,"line":535},15,[276,537,538],{"class":286},"await",[276,540,541],{"class":282}," app",[276,543,287],{"class":286},[276,545,290],{"class":282},[276,547,287],{"class":286},[276,549,550],{"class":295},"SeedOAuthClientsAsync",[276,552,553],{"class":286},"();",[276,555,556],{"class":495}," \u002F\u002F after migrations, when options.Clients is used\n",[558,559,560,582,599,602,623,629,632,639,649,652],"ul",{},[561,562,563,565,566,569,570,573,574,577,578,581],"li",{},[233,564,529],{}," maps the authorization server, the JSON consent API (",[233,567,568],{},"\u002Foauth","), and developer app management (",[233,571,572],{},"\u002Foauth\u002Fapps","). Turn the consent API or developer apps off, or move them, with ",[233,575,576],{},"app.MapOAuthServer(parts => …)",". Anonymous (dynamic) registration stays off unless ",[233,579,580],{},"options.DynamicRegistration.Enabled"," is set. The recipe does not seed configured clients, because only the host knows when its migrations have run.",[561,583,584,585,588,589,588,592,588,595,598],{},"The building blocks (",[233,586,587],{},"AddAuthEndpointsOpenIddict",", ",[233,590,591],{},"MapAuthEndpointsOpenIddict",[233,593,594],{},"MapOAuthConsentEndpoints",[233,596,597],{},"MapOAuthDeveloperAppEndpoints",") stay public for hosts that want them one by one.",[561,600,601],{},"Authorization code + PKCE (S256 only), rotating refresh tokens with no reuse leeway, 15-minute reference access tokens, revocation.",[561,603,604,607,608,611,612,615,616,619,620,287],{},[233,605,606],{},"\u002Fconnect\u002Fauthorize"," sends signed-out users to ",[233,609,610],{},"LoginUrl"," with a ",[233,613,614],{},"returnUrl"," on this server, and signed-in users to ",[233,617,618],{},"ConsentUrl?request={id}",". Your page approves or denies through the consent API or ",[233,621,622],{},"IOAuthConsentService",[561,624,625,626,287],{},"The token subject defaults to the Identity user id. Replace it with ",[233,627,628],{},"IOAuthPrincipalFactory",[561,630,631],{},"Every code exchange and refresh checks the approving user again (exists, can sign in, not locked out, same security stamp). A failed check revokes the grant.",[561,633,634,635,638],{},"Developer apps: signed-in users register OAuth apps they own through the developer app API. A confidential app gets a client secret that is shown once; a public app (SPA, native, CLI) uses PKCE only. Optional admin approval, per-user limits, and secret rotation. The consent card shows a developer app's homepage, description, and whether it is confidential. It shows an owner only through a host ",[233,636,637],{},"IOAuthDeveloperAppOwnerDisplay",", never the owner's email or user name.",[561,640,641,642,588,645,648],{},"Redirect URIs match exactly, except that loopback IP redirects (",[233,643,644],{},"http:\u002F\u002F127.0.0.1",[233,646,647],{},"http:\u002F\u002F[::1]",") may use any port (RFC 8252 §7.3).",[561,650,651],{},"Dynamic client registration and protected resource metadata are off by default.",[561,653,654],{},"HTTPS, resource (audience) validation, and per-client resource permissions are on by default.",[251,656,658],{"id":657},"relation-to-external-sign-in","Relation to external sign-in",[230,660,661,664],{},[245,662,167],{"href":663},"\u002Fmodules\u002Fexternal-oauth\u002F"," signs users in to your app with another provider. This package makes your app the provider. A user who signed in with a cookie-mode external provider can approve an OAuth client like any other signed-in user.",[251,666,668],{"id":667},"limitations","Limitations",[230,670,671,672,675,676,588,679,682,683,686,687,690,691,287],{},"This is a preview. OpenID Connect (ID tokens, ",[233,673,674],{},"userinfo",", logout, and the ",[233,677,678],{},"email",[233,680,681],{},"email_verified",", and ",[233,684,685],{},"amr"," claims) is not supported yet, and only this server can validate its access tokens. The package ",[245,688,248],{"href":689},"https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpoints\u002Ftree\u002Fmain\u002Fsrc\u002FAuthEndpoints.OpenIddict#limitations"," lists every known gap. Remaining work is tracked in ",[245,692,694],{"href":693},"https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpoints\u002Fissues\u002F389","#389",[696,697,698],"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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}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);}",{"title":272,"searchDepth":279,"depth":321,"links":700},[701,702,703],{"id":253,"depth":321,"text":254},{"id":657,"depth":321,"text":658},{"id":667,"depth":321,"text":668},"Opt-in package that lets other apps and tool clients sign users in through your app and get access tokens.","md",null,{},{"title":194,"icon":78},{"title":225,"description":704},"raGCgrdfq0JoaNdgx5UflkfH3oL6dJzW9E1K-RCRt5k",[712,714],{"title":190,"path":191,"stem":192,"description":713,"icon":73,"children":-1},"Reference for emailed one-time codes, optional sign-up, and optional magic links.",{"title":204,"path":205,"stem":206,"description":715,"icon":207,"children":-1},"How AuthEndpoints differs from wiring Identity yourself, from OpenIddict, and from MapIdentityApi.",1793899905767]