OAuth server (OpenIddict)
AuthEndpoints.OpenIddict (preview) turns an AuthEndpoints app into an OAuth 2.0 authorization server, built on OpenIddict 7.7. The core AuthEndpoints package does not change and has no OpenIddict dependency.
The package README covers setup, the consent step, certificates, dynamic registration, and every setting.
In short
The default recipe is one registration call and one map call, like AddPasswordAuth / MapPasswordAuth:
builder.Services.AddOAuthServer<AppUser, AppDbContext>(options =>
{
options.Issuer = new Uri("https://auth.example.com/");
options.Audience = "https://api.example.com/";
options.Scopes.Add("api");
options.LoginUrl = "https://app.example.com/sign-in";
options.ConsentUrl = "https://app.example.com/oauth/consent";
options.Certificates.Path = "/var/lib/myapp/oauth-keys";
});
// OnModelCreating
builder.UseAuthEndpointsOpenIddict<AppUser>();
app.MapOAuthServer();
await app.Services.SeedOAuthClientsAsync(); // after migrations, when options.Clients is used
MapOAuthServermaps the authorization server, the JSON consent API (/oauth), and developer app management (/oauth/apps). Turn the consent API or developer apps off, or move them, withapp.MapOAuthServer(parts => …). Anonymous (dynamic) registration stays off unlessoptions.DynamicRegistration.Enabledis set. The recipe does not seed configured clients, because only the host knows when its migrations have run.- The building blocks (
AddAuthEndpointsOpenIddict,MapAuthEndpointsOpenIddict,MapOAuthConsentEndpoints,MapOAuthDeveloperAppEndpoints) stay public for hosts that want them one by one. - Authorization code + PKCE (S256 only), rotating refresh tokens with no reuse leeway, 15-minute reference access tokens, revocation.
/connect/authorizesends signed-out users toLoginUrlwith areturnUrlon this server, and signed-in users toConsentUrl?request={id}. Your page approves or denies through the consent API orIOAuthConsentService.- The token subject defaults to the Identity user id. Replace it with
IOAuthPrincipalFactory. - 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.
- 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
IOAuthDeveloperAppOwnerDisplay, never the owner's email or user name. - Redirect URIs match exactly, except that loopback IP redirects (
http://127.0.0.1,http://[::1]) may use any port (RFC 8252 §7.3). - Dynamic client registration and protected resource metadata are off by default.
- HTTPS, resource (audience) validation, and per-client resource permissions are on by default.
Relation to external sign-in
External OAuth 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.
Limitations
This is a preview. OpenID Connect (ID tokens, userinfo, logout, and the email, email_verified, and amr claims) is not supported yet, and only this server can validate its access tokens. The package README lists every known gap. Remaining work is tracked in #389.