OpenIddict

Authentication Library.NETOAuth2OpenID ConnectASP.NET CoreJWTAuthenticationAuthorization

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

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;
            }));
    });