Adding OpenIddict 3.0 to an OWIN application

Last year, I announced that OpenIddict would become compatible with OWIN/Katana – and thus usable in any ASP.NET 4.x non-Core application – as part of the 3.0 release. While using OpenIddict in an OWIN application shouldn't be much different than using it in an ASP.NET Core application, there's actually a part than will sightly differ between the two platforms: dependency injection.

Globally introduced in ASP.NET Core 1.0, dependency injection support was not a thing in OWIN. Yet, OpenIddict itself depends on dependency injection for all its features: core, server and token validation. To work around the lack of official DI support, OpenIddict 3.0 will support two approaches: one working with the Autofac DI container and one without. This blog post briefly describes how to do that.

To keep things simple, we'll create a tiny self-hosted .NET 4.7.2 OWIN application, but of course, these 2 approaches also work in any ASP.NET application, no matter what's the host used: HttpListener, System.Web or even third-party options like Nowin.

For that, create a new application with the following .csproj, that contains the basic things we'll need: the Microsoft DI primitives used by OpenIddict, the OWIN self-host and hosting abstractions and the OpenIddict OWIN metapackage (that itself references the core, server and validation packages, plus the OWIN integration assembly):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.2" />
<PackageReference Include="Microsoft.Owin.Host.HttpListener" Version="4.1.0" />
<PackageReference Include="Microsoft.Owin.Hosting" Version="4.1.0" />
<PackageReference Include="OpenIddict.Owin" Version="3.0.0-alpha1.20129.65" />
</ItemGroup>
</Project>

At the time of writing, OpenIddict 3.0's prelease packages are not yet available on NuGet.org. To use the nightly builds, you need to reference the dedicated OpenIddict MyGet feed: https://www.myget.org/F/openiddict/api/v3/index.json

Then, add the entry point...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using Microsoft.Owin.Hosting;
namespace OpenIddictWebApiDemo
{
public static class Program
{
public static void Main(string[] args)
{
const string address = "http://localhost:58779/";
using (WebApp.Start<Startup>(address))
{
Console.WriteLine($"Server is running on {address}, press CTRL+C to stop.");
Console.ReadLine();
}
}
}
}

... and the Startup class:

1
2
3
4
5
6
7
8
9
10
11
using Owin;
namespace OpenIddictWebApiDemo
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
}
}
}

At this point, no matter the option you'll opt for, you'll need to instantiate a ServiceCollection and register the OpenIddict server services (exactly like how you'd do in a ASP.NET Core application):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public void Configuration(IAppBuilder app)
{
var services = new ServiceCollection();
services.AddOpenIddict()
.AddServer(options =>
{
options.AllowPasswordFlow();
options.EnableDegradedMode();
options.AcceptAnonymousClients();
options.SetTokenEndpointUris("/connect/token");
options.AddDevelopmentEncryptionCertificate()
.AddDevelopmentSigningCertificate();
options.UseOwin()
.DisableTransportSecurityRequirement();
options.AddEventHandler<ValidateTokenRequestContext>(b =>
b.UseInlineHandler(context =>
{
// Client authentication is used in this sample,
// so there's nothing to validate here.
return default;
}));
options.AddEventHandler<HandleTokenRequestContext>(b =>
b.UseInlineHandler(context =>
{
if (!context.Request.IsPasswordGrantType())
{
throw new InvalidOperationException("The specified grant type is not supported.");
}
// Validate the username/password parameters.
// In a real world application, you'd use likely use a key derivation function like PBKDF2 to slow
// the client secret validation process down and a time-constant comparer to prevent timing attacks.
if (!string.Equals(context.Request.Username, "alice@wonderland.com", StringComparison.Ordinal) ||
!string.Equals(context.Request.Password, "P@ssw0rd", StringComparison.Ordinal))
{
context.Reject(
error: Errors.InvalidGrant,
description: "The username/password couple is invalid.");
return default;
}
var principal = new ClaimsPrincipal(new ClaimsIdentity(OpenIddictServerOwinDefaults.AuthenticationType));
principal.SetClaim(Claims.Subject, "Bob");
context.Principal = principal;
return default;
}));
});
}

If you read my previous post, you probably figured out that I used OpenIddict 3.0's degraded mode in this snippet to implement the OAuth 2.0 password flow, which allows using OpenIddict's server feature without any backing database.

If you try to run the project as-is, all you'll get is a 404 error, as there's still a thing we need to do: integrating OpenIddict into OWIN's request processing pipeline.

Unlike most other DI containers, Autofac has an excellent OWIN integration story that keeps things very clean and well-integrated. To use Autofac with OWIN, reference the following packages:

1
2
<PackageReference Include="Autofac.Owin" Version="5.0.1" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="6.0.0" />

Then, update your Configuration method to create the IContainer, import the ServiceCollection and register the Autofac OWIN middleware:

1
2
3
4
5
6
7
8
9
10
11
12
public void Configuration(IAppBuilder app)
{
var services = new ServiceCollection();
// ...
var builder = new ContainerBuilder();
builder.Populate(services);
var container = builder.Build();
app.UseAutofacMiddleware(container);
}

This is the beauty of this option: nothing else is required.

Using OpenIddict 3.0 without Autofac

Without Autofac, things will get a bit more complicated, as you'll need to manage per-request scopes yourself. While we'll use the Microsoft DI container to achieve that, this approach is also doable with any other DI container that provides an IServiceProvider implementation.

For that, we'll have to add a middleware creating a service scope per request and injecting it in the OWIN environment with the System.IServiceProvider key (the value that the OpenIddict server OWIN integration expects). We'll also need to call app.UseOpenIddictServer(), that registers the OpenIddict OWIN authentication handler (which is not called when using Autofac).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public void Configuration(IAppBuilder app)
{
var services = new ServiceCollection();
// ...
var container = services.BuildServiceProvider();
app.Use(async (context, next) =>
{
var scope = container.CreateScope();
// Store the per-request service provider in the OWIN environment.
context.Set(typeof(IServiceProvider).FullName, scope.ServiceProvider);
try
{
// Invoke the rest of the pipeline.
await next();
}
finally
{
// Remove the scoped service provider from the OWIN environment.
context.Set<IServiceProvider>(typeof(IServiceProvider).FullName, null);
// Dispose of the scoped service provider.
if (scope is IAsyncDisposable disposable)
{
await disposable.DisposeAsync();
}
else
{
scope.Dispose();
}
}
});
app.UseOpenIddictServer();
}

To ensure things are working properly, you can use Postman and send a token request:

postman.png