[{"data":1,"prerenderedAt":347},["ShallowReactive",2],{"blog-post-\u002Fblog\u002Fauthendpoints-3-0-rc":3,"blog-surround-\u002Fblog\u002Fauthendpoints-3-0-rc":340},{"id":4,"title":5,"authors":6,"badge":12,"body":14,"date":322,"description":323,"extension":324,"image":325,"meta":327,"navigation":77,"path":335,"seo":336,"stem":338,"__hash__":339},"posts\u002Fblog\u002Fauthendpoints-3-0-rc.md","AuthEndpoints 3.0 RC: a composable auth endpoints library for ASP.NET Core",[7],{"name":8,"to":9,"avatar":10},"Made Y","\u002F",{"src":11},"\u002Fimages\u002Fprofile2.jpg",{"label":13},"Open Source",{"type":15,"value":16,"toc":312},"minimark",[17,21,24,29,32,37,40,44,47,51,54,153,156,160,193,197,208,211,222,225,229,259,262,308],[18,19,20],"p",{},"Today I'm releasing AuthEndpoints 3.0 RC: an auth library for ASP.NET Core that turns auth setup from a project phase into a setup step.",[18,22,23],{},"If you build ASP.NET Core backends or web APIs, you may have written this before. Register, login, email confirmation, password reset, 2FA, session management. Same code in every project, different user model each time. AuthEndpoints packages that work into a library on top of ASP.NET Core Identity, so a secure auth layer takes minutes to stand up instead of a week of copy-paste.",[25,26,28],"h2",{"id":27},"why-its-good-for-developer-productivity","Why it's good for developer productivity",[18,30,31],{},"Two design decisions drive most of the value.",[33,34,36],"h3",{"id":35},"opinionated-options","Opinionated options.",[18,38,39],{},"Auth comes with a lot of decisions, and most of them have one right answer for a web frontend backed by a single API. AuthEndpoints bakes those in: rate limiting, antiforgery, lockout-aware login, and hashed refresh tokens with reuse detection are on by default. The hardened path is the default path, so you don't have to know the pitfalls to avoid them.",[33,41,43],{"id":42},"composable-endpoints","Composable endpoints.",[18,45,46],{},"AuthEndpoints is organized as endpoints and modules you can compose manually. Need email\u002Fpassword with JWT? Cookie sessions with passkeys? 2FA on top of that? You pick the pieces, and the routes and validation stay consistent across the whole setup.",[25,48,50],{"id":49},"the-quick-start","The quick start",[18,52,53],{},"Three extension methods and a few lines:",[55,56,61],"pre",{"className":57,"code":58,"language":59,"meta":60,"style":60},"language-cs shiki shiki-themes material-theme-lighter github-light github-dark monokai","builder.Services.AddDbContext\u003CAppDbContext>(\u002F* your provider *\u002F);\n\nbuilder.Services.AddAuthEndpoints\u003CAppUser, AppDbContext>(o =>\n{\n    o.Passkeys.ServerDomain = \"example.com\"; \u002F\u002F required in Production\n});\n\nbuilder.Services.AddTransient\u003CIEmailSender\u003CAppUser>, MyEmailSender>();\n\nvar app = builder.Build();\n\napp.UseAuthEndpoints();\napp.MapAuthEndpoints\u003CAppUser>();\n\napp.Run();\n","cs","",[62,63,64,72,79,85,91,97,103,108,114,119,125,130,136,142,147],"code",{"__ignoreMap":60},[65,66,69],"span",{"class":67,"line":68},"line",1,[65,70,71],{},"builder.Services.AddDbContext\u003CAppDbContext>(\u002F* your provider *\u002F);\n",[65,73,75],{"class":67,"line":74},2,[65,76,78],{"emptyLinePlaceholder":77},true,"\n",[65,80,82],{"class":67,"line":81},3,[65,83,84],{},"builder.Services.AddAuthEndpoints\u003CAppUser, AppDbContext>(o =>\n",[65,86,88],{"class":67,"line":87},4,[65,89,90],{},"{\n",[65,92,94],{"class":67,"line":93},5,[65,95,96],{},"    o.Passkeys.ServerDomain = \"example.com\"; \u002F\u002F required in Production\n",[65,98,100],{"class":67,"line":99},6,[65,101,102],{},"});\n",[65,104,106],{"class":67,"line":105},7,[65,107,78],{"emptyLinePlaceholder":77},[65,109,111],{"class":67,"line":110},8,[65,112,113],{},"builder.Services.AddTransient\u003CIEmailSender\u003CAppUser>, MyEmailSender>();\n",[65,115,117],{"class":67,"line":116},9,[65,118,78],{"emptyLinePlaceholder":77},[65,120,122],{"class":67,"line":121},10,[65,123,124],{},"var app = builder.Build();\n",[65,126,128],{"class":67,"line":127},11,[65,129,78],{"emptyLinePlaceholder":77},[65,131,133],{"class":67,"line":132},12,[65,134,135],{},"app.UseAuthEndpoints();\n",[65,137,139],{"class":67,"line":138},13,[65,140,141],{},"app.MapAuthEndpoints\u003CAppUser>();\n",[65,143,145],{"class":67,"line":144},14,[65,146,78],{"emptyLinePlaceholder":77},[65,148,150],{"class":67,"line":149},15,[65,151,152],{},"app.Run();\n",[18,154,155],{},"That maps the whole account lifecycle: register, confirm email, forgot and reset password, manage info and 2FA, plus step-up re-authentication for sensitive actions. You bring the DbContext and an email sender. The library handles the rest, including your choice of cookie sessions, Identity bearer tokens, or Simple JWT, and passkeys (WebAuthn) for passwordless sign-in.",[25,157,159],{"id":158},"whats-in-30","What's in 3.0",[161,162,163,171,177,183],"ul",{},[164,165,166,170],"li",{},[167,168,169],"strong",{},"Sign-in stacks you pick",": cookie sessions, Identity bearer tokens, or Simple JWT. The endpoints stay the same; the token strategy is configuration.",[164,172,173,176],{},[167,174,175],{},"Passkeys (WebAuthn)"," for passwordless register and login, working alongside email\u002Fpassword rather than replacing it.",[164,178,179,182],{},[167,180,181],{},"Hardening on by default",": the opinionated defaults, enabled without extra setup.",[164,184,185,188,189,192],{},[167,186,187],{},"GitHub and Google OAuth"," through an optional separate package, ",[62,190,191],{},"AuthEndpoints.External.OAuth",".",[25,194,196],{"id":195},"help-shape-the-final-api","Help shape the final API",[18,198,199,200,207],{},"3.0 is a rewrite, and the API isn't frozen yet. An RC is the last moment to change things cheaply; once 3.0 ships stable, breaking changes cost everyone who adopted it. If you try it and something feels off, please ",[201,202,206],"a",{"href":203,"rel":204},"https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpoints\u002Fissues",[205],"nofollow","open an issue",". Your feedback decides what the API looks like when it ships.",[18,209,210],{},"In particular, I'd love to hear:",[161,212,213,216,219],{},[164,214,215],{},"Do naming or composition feel awkward for your app?",[164,217,218],{},"Are the defaults too strict or too loose?",[164,220,221],{},"Is a module missing that you'd need in a real project?",[18,223,224],{},"Mention which stack you used (cookies, JWT, passkeys) and what you were trying to do. No template required.",[25,226,228],{"id":227},"try-it","Try it",[55,230,234],{"className":231,"code":232,"language":233,"meta":60,"style":60},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark monokai","dotnet add package AuthEndpoints --version 3.0.0-rc.3\n","bash",[62,235,236],{"__ignoreMap":60},[65,237,238,242,246,249,252,256],{"class":67,"line":68},[65,239,241],{"class":240},"sR7ES","dotnet",[65,243,245],{"class":244},"sLACW"," add",[65,247,248],{"class":244}," package",[65,250,251],{"class":244}," AuthEndpoints",[65,253,255],{"class":254},"sFhLe"," --version",[65,257,258],{"class":244}," 3.0.0-rc.3\n",[18,260,261],{},"Install the package, or open the demo and click through the flows. If something feels awkward, breaks, or is missing, open an issue — that's how 3.0 stable gets shaped.",[161,263,264,276,286,297],{},[164,265,266,269,270,275],{},[167,267,268],{},"Demo app",": ",[201,271,274],{"href":272,"rel":273},"https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpointsDemo",[205],"madeyoga\u002FAuthEndpointsDemo",", an ASP.NET Core API plus a Nuxt 4 \u002F Nuxt UI playground, so you can click through the flows without writing a frontend first.",[164,277,278,281,282,192],{},[167,279,280],{},"Feedback",": open an issue on ",[201,283,285],{"href":203,"rel":284},[205],"madeyoga\u002FAuthEndpoints",[164,287,288,269,291,296],{},[167,289,290],{},"Docs",[201,292,295],{"href":293,"rel":294},"https:\u002F\u002Fmadeyoga.github.io\u002FAuthEndpoints\u002F",[205],"madeyoga.github.io\u002FAuthEndpoints"," with configuration, composable modules, route tables, and production guidance.",[164,298,299,269,302,307],{},[167,300,301],{},"Repository",[201,303,306],{"href":304,"rel":305},"https:\u002F\u002Fgithub.com\u002Fmadeyoga\u002FAuthEndpoints",[205],"AuthEndpoints"," (MIT).",[309,310,311],"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 .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html pre.shiki code .sR7ES, html code.shiki .sR7ES{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sFhLe, html code.shiki .sFhLe{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}",{"title":60,"searchDepth":74,"depth":81,"links":313},[314,318,319,320,321],{"id":27,"depth":74,"text":28,"children":315},[316,317],{"id":35,"depth":81,"text":36},{"id":42,"depth":81,"text":43},{"id":49,"depth":74,"text":50},{"id":158,"depth":74,"text":159},{"id":195,"depth":74,"text":196},{"id":227,"depth":74,"text":228},"2026-08-01","Announcing AuthEndpoints 3.0 RC, an auth library for ASP.NET Core. Composable auth endpoints on top of ASP.NET Core Identity: registration, login, 2FA, password reset, and passkeys bootstrapped in minutes.","md",{"src":326},"\u002Fimages\u002Fauthendpoints-3-0-rc.png",{"sitemap":328,"schemaOrg":329},{"lastmod":322},[330],{"type":331,"headline":5,"author":332,"datePublished":322},"BlogPosting",{"type":333,"name":334},"Person","Made Yoga","\u002Fblog\u002Fauthendpoints-3-0-rc",{"keywords":337,"title":5,"description":323},"AuthEndpoints, ASP.NET Core authentication, .NET 10, passkeys, WebAuthn, JWT, ASP.NET Core Identity, NuGet","blog\u002Fauthendpoints-3-0-rc","iHmoDZuMHLFrRTbTlQ76fR9CGJVvwW43q4Csd4USwj0",[341,346],{"title":342,"path":343,"stem":344,"description":345,"children":-1},"Experimenting with Hermes Agent + DeepSeek-V4-Flash-0731 for ASP.NET Core and Nuxt","\u002Fblog\u002Fai-agent-workflow-deepseek-hermes","blog\u002Fai-agent-workflow-deepseek-hermes","Lab notes on running Hermes Agent with DeepSeek-V4-Flash-0731 beta — teaching .NET and Nuxt via skills, wiring Nuxt and Nuxt UI MCPs, and what still feels rough.",null,1785600513179]