OpenIddict
Authentication Library
OpenIddict
Overview
OpenIddict is a flexible and versatile OAuth 2.0/OpenID Connect stack for .NET applications.
Details
OpenIddict is a modern authentication framework that provides implementation of OAuth 2.0 and OpenID Connect protocols for .NET applications. Developed by Microsoft and provided as open source, OpenIddict offers three independent stacks (server, client, validation) that can be configured individually according to developer needs. It provides complete control at the protocol level, enabling implementation of custom authentication logic. Supporting multiple data storage options including Entity Framework Core, MongoDB, and custom providers, it integrates with various hosting platforms such as ASP.NET Core and OWIN/Katana. OpenIddict focuses exclusively on the OAuth 2.0/OpenID Connect aspects of the authentication process, leaving user authentication to the implementer for maximum flexibility.
Pros and Cons
Pros
- Protocol Compliance: Complete implementation of OAuth 2.0 and OpenID Connect
- High Flexibility: Three independent stacks (server, client, validation)
- Multiple Flow Support: Authorization code, client credentials, hybrid flows all supported
- Storage Abstraction: Entity Framework, MongoDB, custom provider support
- Platform Independence: ASP.NET Core and OWIN support
- Enterprise Ready: Practical for large-scale applications
- OpenID Connect Certification: Compatible with certified implementations
Cons
- Learning Curve: Requires OAuth 2.0/OpenID Connect knowledge
- Configuration Complexity: Advanced features require detailed configuration
- Documentation: Advanced use cases require extensive documentation reference
- Debugging Difficulty: Protocol-level issues can be hard to diagnose
- .NET Dependency: Cannot be used outside .NET ecosystem
Key Links
- OpenIddict Official Site
- OpenIddict GitHub
- OpenIddict Documentation
- OpenIddict Samples
- NuGet Package
Code Examples
Basic Server Configuration
// Program.cs or Startup.cs
services.AddOpenIddict()
.AddServer(options =>
{
// Configure endpoints
options.SetTokenEndpointUris("connect/token")
.SetAuthorizationEndpointUris("connect/authorize");
// Enable grant types
options.AllowAuthorizationCodeFlow()
.AllowClientCredentialsFlow()
.AllowRefreshTokenFlow();
// Add development certificates
options.AddDevelopmentEncryptionCertificate()
.AddDevelopmentSigningCertificate();
// ASP.NET Core integration
options.UseAspNetCore()
.EnableTokenEndpointPassthrough()
.EnableAuthorizationEndpointPassthrough();
});
Client Configuration (External Provider)
services.AddOpenIddict()
.AddClient(options =>
{
// Enable authorization code flow
options.AllowAuthorizationCodeFlow();
// Configure encryption certificates
options.AddDevelopmentEncryptionCertificate()
.AddDevelopmentSigningCertificate();
// ASP.NET Core integration
options.UseAspNetCore()
.EnableRedirectionEndpointPassthrough();
// System.Net.Http integration
options.UseSystemNetHttp();
// GitHub integration
options.UseWebProviders()
.AddGitHub(options =>
{
options.SetClientId("your-client-id")
.SetClientSecret("your-client-secret")
.SetRedirectUri("callback/login/github");
});
});
Token Validation Configuration
services.AddOpenIddict()
.AddValidation(options =>
{
// Use OpenID Connect Discovery
options.SetIssuer("https://localhost:44319/");
// Configure encryption keys
options.AddEncryptionKey(new SymmetricSecurityKey(
Convert.FromBase64String("your-encryption-key")));
// System.Net.Http integration
options.UseSystemNetHttp();
// ASP.NET Core integration
options.UseAspNetCore();
});
Authorization Controller
[ApiController]
public class AuthorizationController : ControllerBase
{
[HttpPost("~/connect/token")]
public async Task<IActionResult> Exchange()
{
var request = HttpContext.GetOpenIddictServerRequest();
if (request.IsClientCredentialsGrantType())
{
var identity = new ClaimsIdentity(
TokenValidationParameters.DefaultAuthenticationType,
Claims.Name,
Claims.Role);
identity.SetClaim(Claims.Subject, request.ClientId);
identity.SetClaim(Claims.Name, "API Client");
identity.SetDestinations(static claim => claim.Type switch
{
Claims.Name when claim.Subject.HasScope(Scopes.Profile)
=> new[] { Destinations.AccessToken, Destinations.IdentityToken },
_ => new[] { Destinations.AccessToken }
});
return SignIn(new ClaimsPrincipal(identity),
OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
}
throw new NotImplementedException("The specified grant is not implemented.");
}
}
Client Credentials Flow Usage
// Get service from DI container
var service = serviceProvider.GetRequiredService<OpenIddictClientService>();
// Obtain access token
var result = await service.AuthenticateWithClientCredentialsAsync(new());
var accessToken = result.AccessToken;
// Use in API requests
using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
var response = await httpClient.GetAsync("https://api.example.com/data");
Application Registration (Programmatic)
public class Worker : IHostedService
{
private readonly IServiceProvider _serviceProvider;
public async Task StartAsync(CancellationToken cancellationToken)
{
using var scope = _serviceProvider.CreateScope();
var manager = scope.ServiceProvider
.GetRequiredService<IOpenIddictApplicationManager>();
if (await manager.FindByClientIdAsync("api-client") is null)
{
await manager.CreateAsync(new OpenIddictApplicationDescriptor
{
ClientId = "api-client",
ClientSecret = "your-client-secret",
Permissions =
{
Permissions.Endpoints.Token,
Permissions.GrantTypes.ClientCredentials,
Permissions.Scopes.Profile
}
});
}
}
}
Advanced Configuration (Custom Event Handler)
services.AddOpenIddict()
.AddServer(options =>
{
options.AddEventHandler<HandleConfigurationRequestContext>(builder =>
builder.UseInlineHandler(context =>
{
// Add custom metadata
context.Metadata["custom_metadata"] = "custom_value";
return default;
}));
});