Merge pull request #2307 from DuendeSoftware/ev/bff/dpop-issue

BFF should use the `AccessToken` instead of the serialized version of the token representation
This commit is contained in:
Erwin van der Valk 2025-12-12 15:23:55 +01:00 committed by Pieter Germishuys
parent fcfbc9645e
commit fe96f97dae
5 changed files with 56 additions and 21 deletions

View file

@ -40,7 +40,7 @@ that supports the target frameworks our products target (8, 9, 10) -->
<PackageVersion Include="KubernetesClient" Version="17.0.14" />
<PackageVersion Include="Duende.AccessTokenManagement" Version="4.1.0" />
<PackageVersion Include="Duende.AccessTokenManagement.OpenIdConnect" Version="4.1.0" />
<PackageVersion Include="Duende.AspNetCore.Authentication.JwtBearer" Version="0.1.3" />
<PackageVersion Include="Duende.AspNetCore.Authentication.JwtBearer" Version="0.3.0" />
<PackageVersion Include="Duende.IdentityModel" Version="8.0.0" />
<PackageVersion Include="Duende.IdentityModel.OidcClient" Version="7.0.0" />
<PackageVersion Include="Duende.IdentityServer" Version="7.4.0-preview.2" />
@ -136,4 +136,4 @@ that supports the target frameworks our products target (8, 9, 10) -->
<PackageVersion Include="Vogen" Version="7.0.3" />
<PackageVersion Include="Yarp.ReverseProxy" Version="2.1.0" />
</ItemGroup>
</Project>
</Project>

View file

@ -2,8 +2,6 @@
"solution": {
"path": "..\\products.slnx",
"projects": [
"bff\\performance\\Bff.Benchmarks\\Bff.Benchmarks.csproj",
"bff\\performance\\Bff.Performance\\Bff.Performance.csproj",
".github\\workflow-gen\\workflow-gen.csproj",
"bff\\hosts\\Blazor\\PerComponent\\Hosts.Bff.Blazor.PerComponent.Client\\Hosts.Bff.Blazor.PerComponent.Client.csproj",
"bff\\hosts\\Blazor\\PerComponent\\Hosts.Bff.Blazor.PerComponent\\Hosts.Bff.Blazor.PerComponent.csproj",
@ -13,8 +11,8 @@
"bff\\hosts\\Hosts.Bff.DPoP\\Hosts.Bff.DPoP.csproj",
"bff\\hosts\\Hosts.Bff.EF\\Hosts.Bff.EF.csproj",
"bff\\hosts\\Hosts.Bff.InMemory\\Hosts.Bff.InMemory.csproj",
"bff\\hosts\\Hosts.Bff.Performance\\Hosts.Bff.Performance.csproj",
"bff\\hosts\\Hosts.Bff.MultiFrontend\\Hosts.Bff.MultiFrontend.csproj",
"bff\\hosts\\Hosts.Bff.Performance\\Hosts.Bff.Performance.csproj",
"bff\\hosts\\Hosts.IdentityServer\\Hosts.IdentityServer.csproj",
"bff\\hosts\\Hosts.ServiceDefaults\\Hosts.ServiceDefaults.csproj",
"bff\\hosts\\RemoteApis\\Hosts.RemoteApi.DPoP\\Hosts.RemoteApi.DPoP.csproj",
@ -22,6 +20,7 @@
"bff\\hosts\\RemoteApis\\Hosts.RemoteApi\\Hosts.RemoteApi.csproj",
"bff\\migrations\\UserSessionDb\\UserSessionDb.csproj",
"bff\\performance\\Bff.Benchmarks\\Bff.Benchmarks.csproj",
"bff\\performance\\Bff.Performance\\Bff.Performance.csproj",
"bff\\src\\Bff.Blazor.Client\\Bff.Blazor.Client.csproj",
"bff\\src\\Bff.Blazor\\Bff.Blazor.csproj",
"bff\\src\\Bff.EntityFramework\\Bff.EntityFramework.csproj",
@ -33,8 +32,8 @@
"bff\\templates\\src\\BffRemoteApi\\BffRemoteApi.csproj",
"bff\\test\\Bff.Tests\\Bff.Tests.csproj",
"bff\\test\\Hosts.Tests\\Hosts.Tests.csproj",
"shared\\Xunit.Playwright\\Duende.Xunit.Playwright.csproj",
"shared\\ShouldlyExtensions\\ShouldlyExtensions.csproj"
"shared\\ShouldlyExtensions\\ShouldlyExtensions.csproj",
"shared\\Xunit.Playwright\\Duende.Xunit.Playwright.csproj"
]
}
}
}

View file

@ -95,7 +95,7 @@ internal static class HttpContextExtensions
return new DPoPTokenResult()
{
AccessToken = AccessToken.Parse(userToken.ToString()),
AccessToken = AccessToken.Parse(userToken.AccessToken.ToString()),
DPoPJsonWebKey = DPoPProofKey.Parse(userToken.DPoPJsonWebKey!.ToString()!)
};
}
@ -156,7 +156,7 @@ internal static class HttpContextExtensions
return new DPoPTokenResult()
{
AccessToken = AccessToken.Parse(clientToken.ToString()),
AccessToken = AccessToken.Parse(clientToken.AccessToken.ToString()),
DPoPJsonWebKey = DPoPProofKey.Parse(clientToken.DPoPJsonWebKey!.ToString()!)
};

View file

@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Duende.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Duende.IdentityServer" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" />

View file

@ -1,6 +1,7 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.
using Duende.AspNetCore.Authentication.JwtBearer.DPoP;
using Duende.Bff.AccessTokenManagement;
using Duende.Bff.Tests.TestFramework;
using Duende.Bff.Tests.TestInfra;
@ -9,7 +10,7 @@ using Xunit.Abstractions;
namespace Duende.Bff.Tests.Endpoints;
public class DpopRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(output), IAsyncLifetime
public class DPoPRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(output)
{
public override async Task InitializeAsync()
{
@ -18,11 +19,7 @@ public class DpopRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(out
idSrvClient.RequireDPoP = true;
Bff.OnConfigureBff += bff => bff.AddRemoteApis();
Bff.OnConfigureApp += app =>
{
app.MapRemoteBffApiEndpoint(The.Path, Api.Url())
.WithAccessToken(RequiredTokenType.Client);
};
await base.InitializeAsync();
Bff.BffOptions.DPoPJsonWebKey = The.DPoPJsonWebKey;
@ -34,17 +31,55 @@ public class DpopRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(out
}
[Fact]
public async Task Can_login_with_dpop_enabled() => await Bff.BrowserClient.Login()
.CheckHttpStatusCode();
[Fact]
public async Task When_calling_api_endpoint_with_dpop_enabled_then_dpop_headers_are_sent()
public async Task Can_call_dpop_protected_api_with_user_token()
{
Api.OnConfigureServices += services =>
{
services.ConfigureDPoPTokensForScheme("token");
};
Bff.OnConfigureApp += app =>
{
app.MapRemoteBffApiEndpoint(The.Path, Api.Url())
.WithAccessToken(RequiredTokenType.User);
};
await InitializeAsync();
await Bff.BrowserClient.Login()
.CheckHttpStatusCode();
ApiCallDetails callToApi = await Bff.BrowserClient.CallBffHostApi(
url: Bff.Url(The.PathAndSubPath)
);
callToApi.RequestHeaders["DPoP"].First().ShouldNotBeNullOrEmpty();
callToApi.RequestHeaders["Authorization"].First().StartsWith("DPoP ").ShouldBeTrue();
callToApi.Sub.ShouldNotBeNullOrEmpty();
}
[Fact]
public async Task Can_call_dpop_protected_api_with_client_token()
{
Api.OnConfigureServices += services =>
{
services.ConfigureDPoPTokensForScheme("token");
};
Bff.OnConfigureApp += app =>
{
app.MapRemoteBffApiEndpoint(The.Path, Api.Url())
.WithAccessToken(RequiredTokenType.Client);
};
await InitializeAsync();
ApiCallDetails callToApi = await Bff.BrowserClient.CallBffHostApi(
url: Bff.Url(The.PathAndSubPath)
);
callToApi.RequestHeaders["DPoP"].First().ShouldNotBeNullOrEmpty();
callToApi.RequestHeaders["Authorization"].First().StartsWith("DPoP ").ShouldBeTrue();
callToApi.ClientId.ShouldNotBeNullOrEmpty();
}
}