Skip to content

Commit 60a588f

Browse files
committed
Bump OpenIddict to 7.4.0 and update all the samples to use mTLS or client assertions
1 parent 17c82e1 commit 60a588f

47 files changed

Lines changed: 1012 additions & 189 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Directory.Packages.props

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@
4444
<PackageVersion Include="Microsoft.Owin.Security.OAuth" Version="4.2.3" />
4545
<PackageVersion Include="Microsoft.Web.Infrastructure" Version="2.0.1" />
4646
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
47-
<PackageVersion Include="OpenIddict.Client.SystemIntegration" Version="7.3.0" />
48-
<PackageVersion Include="OpenIddict.Client.SystemNetHttp" Version="7.3.0" />
49-
<PackageVersion Include="OpenIddict.EntityFramework" Version="7.3.0" />
50-
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.3.0" />
51-
<PackageVersion Include="OpenIddict.Owin" Version="7.3.0" />
47+
<PackageVersion Include="OpenIddict.Client.SystemIntegration" Version="7.4.0" />
48+
<PackageVersion Include="OpenIddict.Client.SystemNetHttp" Version="7.4.0" />
49+
<PackageVersion Include="OpenIddict.EntityFramework" Version="7.4.0" />
50+
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.4.0" />
51+
<PackageVersion Include="OpenIddict.Owin" Version="7.4.0" />
5252
<PackageVersion Include="WebGrease" Version="1.6.0" />
5353
</ItemGroup>
5454

@@ -89,15 +89,15 @@
8989
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.3.0" />
9090
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.3.0" />
9191
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery.Yarp" Version="10.3.0" />
92-
<PackageVersion Include="OpenIddict.Abstractions" Version="7.3.0" />
93-
<PackageVersion Include="OpenIddict.AspNetCore" Version="7.3.0" />
94-
<PackageVersion Include="OpenIddict.Client.SystemIntegration" Version="7.3.0" />
95-
<PackageVersion Include="OpenIddict.Client.SystemNetHttp" Version="7.3.0" />
96-
<PackageVersion Include="OpenIddict.Client.WebIntegration" Version="7.3.0" />
97-
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.3.0" />
98-
<PackageVersion Include="OpenIddict.Quartz" Version="7.3.0" />
99-
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="7.3.0" />
100-
<PackageVersion Include="OpenIddict.Validation.SystemNetHttp" Version="7.3.0" />
92+
<PackageVersion Include="OpenIddict.Abstractions" Version="7.4.0" />
93+
<PackageVersion Include="OpenIddict.AspNetCore" Version="7.4.0" />
94+
<PackageVersion Include="OpenIddict.Client.SystemIntegration" Version="7.4.0" />
95+
<PackageVersion Include="OpenIddict.Client.SystemNetHttp" Version="7.4.0" />
96+
<PackageVersion Include="OpenIddict.Client.WebIntegration" Version="7.4.0" />
97+
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.4.0" />
98+
<PackageVersion Include="OpenIddict.Quartz" Version="7.4.0" />
99+
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="7.4.0" />
100+
<PackageVersion Include="OpenIddict.Validation.SystemNetHttp" Version="7.4.0" />
101101
<PackageVersion Include="Quartz.Extensions.Hosting" Version="3.15.1" />
102102
<PackageVersion Include="Spectre.Console" Version="0.54.0" />
103103
<PackageVersion Include="Yarp.ReverseProxy" Version="2.3.0" />

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@ This repository contains samples demonstrating **how to use [OpenIddict](https:/
44

55
## ASP.NET Core samples
66

7-
- [Aridka](samples/Aridka): client credentials demo, with a .NET console acting as the client.
7+
- [Aridka](samples/Aridka): client credentials demo using mTLS client authentication, with a .NET console acting as the client.
88
- [Balosar](samples/Balosar): authorization code flow demo, with a Blazor WASM application acting as the client.
99
- [Contruum](samples/Contruum): conformance tests project using Razor Pages and 2 hardcoded user identities, meant to be used with [the OIDC certification suite](https://www.certification.openid.net/).
1010
- [Dantooine](samples/Dantooine): backend-for-frontend (BFF) Blazor WASM application hosted in ASP.NET Core with Microsoft YARP for downstream API.
1111
- [Geonosis](sample/Geonosis): Blazor Web with InteractiveAuto mode, backend-for-frontend (BFF) with YARP and token exchange flow to call a downstream API.
12-
- [Hollastin](samples/Hollastin): resource owner password credentials demo, with a .NET console acting as the client.
12+
- [Hollastin](samples/Hollastin): resource owner password credentials demo, with a .NET console using mTLS token binding acting as the client.
1313
- [Imynusoph](samples/Imynusoph): refresh token grant demo, with a .NET console acting as the client.
1414
- [Matty](samples/Matty): device authorization flow demo, with a .NET console acting as the client.
1515
- [Mimban](samples/Mimban): authorization code flow demo using minimal APIs and GitHub delegation for user authentication, with a .NET console acting as the client.
1616
- [Velusia](samples/Velusia): authorization code flow demo, with an ASP.NET Core application acting as the client.
1717
- [Weytta](samples/Weytta): authorization code flow with Integrated Windows Authentication support and a .NET console acting as the client.
18-
- [Zirku](samples/Zirku): authorization code flow demo using minimal APIs with 2 hard-coded user identities, a .NET console and a SPA acting as the clients and two API projects using introspection (Api1) and local validation (Api2).
18+
- [Zirku](samples/Zirku): authorization code flow demo using minimal APIs with 2 hard-coded user identities, a .NET console using mTLS token binding and a SPA acting as the clients and two API projects using introspection (Api1) and local validation (Api2).
1919

2020
## .NET samples
2121

samples/Aridka/Aridka.Client/Program.cs

Lines changed: 132 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System.Net.Http.Headers;
2+
using System.Security.Cryptography.X509Certificates;
23
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.IdentityModel.Tokens;
35
using OpenIddict.Client;
46

57
var services = new ServiceCollection();
@@ -28,10 +30,27 @@
2830
Issuer = new Uri("https://localhost:44385/", UriKind.Absolute),
2931

3032
ClientId = "console",
31-
ClientSecret = "388D45FA-B36B-4988-BA59-B187D329C207"
33+
34+
// Note: instead of sending a client secret, this application authenticates by using
35+
// a self-signed client authentication certificate during the TLS handshake.
36+
SigningCredentials = { GetSelfSignedCertificate() }
3237
});
3338
});
3439

40+
// Register a named HTTP client that will be used to call the demo resource API.
41+
//
42+
// Note: since the authorization server is configured to issue certificate-bound
43+
// access tokens, the client certificate MUST be attached to outgoing HTTP requests
44+
// and the mTLS subdomain (for which TLS client authentication is enabled) MUST be used.
45+
services.AddHttpClient("ApiClient")
46+
.AddAsKeyed()
47+
.ConfigureHttpClient(static client => client.BaseAddress = new Uri("https://mtls.dev.localhost:44385/"))
48+
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
49+
{
50+
ClientCertificateOptions = ClientCertificateOption.Manual,
51+
ClientCertificates = { GetSelfSignedCertificate().Certificate }
52+
});
53+
3554
await using var provider = services.BuildServiceProvider();
3655

3756
var token = await GetTokenAsync(provider);
@@ -52,12 +71,122 @@ static async Task<string> GetTokenAsync(IServiceProvider provider)
5271

5372
static async Task<string> GetResourceAsync(IServiceProvider provider, string token)
5473
{
55-
using var client = provider.GetRequiredService<HttpClient>();
56-
using var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:44385/api/message");
74+
var client = provider.GetRequiredKeyedService<HttpClient>("ApiClient");
75+
using var request = new HttpRequestMessage(HttpMethod.Get, "api/message");
5776
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
5877

5978
using var response = await client.SendAsync(request);
6079
response.EnsureSuccessStatusCode();
6180

6281
return await response.Content.ReadAsStringAsync();
6382
}
83+
84+
static X509SigningCredentials GetSelfSignedCertificate()
85+
{
86+
// Note: OpenIddict only negotiates PKI-based or self-signed mutual
87+
// TLS authentication if the certificate explicitly contains the
88+
// "digitalSignature" key usage and the "clientAuth" extended key usage.
89+
var certificate = X509Certificate2.CreateFromPem(
90+
certPem: $"""
91+
-----BEGIN CERTIFICATE-----
92+
MIIE8zCCAtugAwIBAgIJAI/egicFvVmsMA0GCSqGSIb3DQEBCwUAMCIxIDAeBgNV
93+
BAMTF1NlbGYtc2lnbmVkIGNlcnRpZmljYXRlMCAXDTI2MDMxMTE0MDkwMloYDzIx
94+
MjYwMzExMTQwOTAyWjAiMSAwHgYDVQQDExdTZWxmLXNpZ25lZCBjZXJ0aWZpY2F0
95+
ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL6lxgz4nzb9B/ajfjy+
96+
DKYJR3isyZ3kJg8f5BvKYFKptQTZWk4TJhChYzNrePBq7I/AW20z4Zt4TZvnAC29
97+
z54EZ/9auxXswHN1tNujc1OPtADRlJmWYf/fI+y4cwoPegaPdSS+WRgeigz6BmJu
98+
Oq5J6/IM/eRBqByaZgYU8Acvjxec9fzoKooK94ZoGeoM6q2GVipHzKLgPp4AsqA/
99+
aY9Uz/sb6mjp/wQX4KcIFZLChGcYetuTkPuh6OcnCwApH67NvZB4HwxXDEMKx89V
100+
JkUh8iOt+1Q3s76yfRl3JGcthrrhzojE/3teQpU3F/aKfou4Hagys3WXQv9q8V6m
101+
s0rXEBF2WuXTF5kCdBhvCnFClrokm20ev8T4aSsI8FDXanMhTamHsFYE5eIgZXZy
102+
q4fYcwnfHENGwvxp3w1tsdSqdtRXBUoJQYNbGyVsZeEADFlLERoqe6FRlnvZVtkZ
103+
tThlYKUwWitOdivVuI5h+64HtJbhBvvdGPDVl3WQVDmQ4Z17HpyPCL6uILNlSxIu
104+
Df+CdOZv3/iElSWUkR3WjO0qohv5TEraCwvhXlCyIK37WyzAXr7XVmZUrpmqU2aa
105+
U4tVmt3o5zDorb7MCit9Mn731nfpjC6wSnHD90JGi7fSHUP7+GH0PfWNDSvjRtrY
106+
bBThQA55vqVzcqHe5M6uCCwVAgMBAAGjKjAoMA4GA1UdDwEB/wQEAwIHgDAWBgNV
107+
HSUBAf8EDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAgEAvCjsrSZQ1iKM
108+
B42rDuE/IBbw5BUn12RzX608uG7CnTgiywwKSokspAi+3N7HEH4+8T+urQDQxCv8
109+
aFZ4SpkDM8xXCh0zF9WIRK3kQYF+crNfrsCJaduCQjCozh1NyZe3oFTXxpHuKh7V
110+
ellexvahLJid9a1bVADAIx5cKLEFhkSVh15hcWlphKMkVsA+cI0D22gbMwO2TSkL
111+
+X2C0YQYd0yxrDjZKU2Y5P8vunDCMPS04UsexERRuUCRzFBp7+mt2c1rT0gxta9w
112+
NeuW7ooUIAeMGNUY2FCrUI4OwMlre6knYZST+sfKyLY6r95PtHgXQB5pZ9G6iHu6
113+
FGdqbvdqcqr79l989z6sOo7p4CzX3dxp3rAuBzgY023bTnNZAnEEYSNYd5AJePD2
114+
1ycEXKEh1+GGkF0t5HX3FVe7VC/AEqCpNwaHzW0KQ6wunuqAJNvGa4gpZVqWGw7f
115+
dBhkg+W5itWbAn3giXQQD8yi/0CJzBSj/GFVPWCax3n3dV404DTAqINq1Koix/1i
116+
oOY+/PQEwlk+QZrtvBpPaDIjX7wVMnu7lF6q/d5gws3kHVPW90+8Nk/pXTeXU6mo
117+
hO6dOCwfN1IrRSn1pQ35UsSKPE9/g5gN77hi0v9AK9jtPfLLJQGYvBAjlU7Y3p7R
118+
Sq+yMXEPCIhq0DMdISeTf1Ajy7rYJcI=
119+
-----END CERTIFICATE-----
120+
""",
121+
keyPem: $"""
122+
-----BEGIN RSA PRIVATE KEY-----
123+
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
172+
-----END RSA PRIVATE KEY-----
173+
""");
174+
175+
// On Windows, a certificate loaded from PEM-encoded material is ephemeral and
176+
// cannot be directly used with TLS, as Schannel cannot access it in this case.
177+
//
178+
// To work this limitation, the certificate is exported and re-imported from a
179+
// PFX blob to ensure the private key is persisted in a way that Schannel can use.
180+
//
181+
// In a real world application, the certificate wouldn't be embedded in the source code
182+
// and would be installed in the certificate store, making this workaround unnecessary.
183+
if (OperatingSystem.IsWindows())
184+
{
185+
certificate = X509CertificateLoader.LoadPkcs12(
186+
data: certificate.Export(X509ContentType.Pfx, string.Empty),
187+
password: string.Empty,
188+
keyStorageFlags: X509KeyStorageFlags.DefaultKeySet);
189+
}
190+
191+
return new X509SigningCredentials(certificate);
192+
}

0 commit comments

Comments
 (0)