Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
259 changes: 124 additions & 135 deletions Directory.Packages.props

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion bff/bff.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"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.MultiFrontend\\Hosts.Bff.MultiFrontend.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",
Expand All @@ -30,4 +31,4 @@
"bff\\test\\Hosts.Tests\\Hosts.Tests.csproj"
]
}
}
}
4 changes: 4 additions & 0 deletions bff/docs/.$Bff Multi Frontend.svg.dtmp

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions bff/docs/Bff Multi Frontend.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.

using Duende.AccessTokenManagement.OpenIdConnect;
using Duende.Bff;
using Duende.Bff.AccessTokenManagement;
using Duende.Bff.Blazor;
Expand Down Expand Up @@ -98,7 +99,7 @@
app.MapBffManagementEndpoints();

app.MapRemoteBffApiEndpoint("/remote-apis/user-token", "https://localhost:5010")
.RequireAccessToken(TokenType.User);
.WithAccessToken(RequiredTokenType.User);

app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
"dotnetRunMessages": true,
"launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:5005",
"applicationUrl": "https://localhost:5006",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
}
2 changes: 2 additions & 0 deletions bff/hosts/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

-->
<TargetFramework>net9.0</TargetFramework>
<IsBffProject>true</IsBffProject>

</PropertyGroup>
<Import Project="../../samples.props" />
</Project>
22 changes: 8 additions & 14 deletions bff/hosts/Hosts.AppHost/Hosts.AppHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,28 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Hosts.ServiceDefaults\Hosts.ServiceDefaults.csproj"
IsAspireProjectResource="false" />
<ProjectReference Include="..\Hosts.Bff.MultiFrontend\Hosts.Bff.MultiFrontend.csproj" />
<ProjectReference Include="..\Hosts.ServiceDefaults\Hosts.ServiceDefaults.csproj" IsAspireProjectResource="false" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\migrations\UserSessionDb\UserSessionDb.csproj" />
<ProjectReference Include="..\RemoteApis\Hosts.RemoteApi.DPoP\Hosts.RemoteApi.DPoP.csproj" />
<ProjectReference
Include="..\RemoteApis\Hosts.RemoteApi.Isolated\Hosts.RemoteApi.Isolated.csproj" />
<ProjectReference Include="..\RemoteApis\Hosts.RemoteApi.Isolated\Hosts.RemoteApi.Isolated.csproj" />
<ProjectReference Include="..\RemoteApis\Hosts.RemoteApi\Hosts.RemoteApi.csproj" />
<ProjectReference Include="..\Hosts.Bff.DPoP\Hosts.Bff.DPoP.csproj" />
<ProjectReference Include="..\Hosts.Bff.EF\Hosts.Bff.EF.csproj" />
<ProjectReference Include="..\Hosts.Bff.InMemory\Hosts.Bff.InMemory.csproj" />
<ProjectReference
Include="..\Blazor\PerComponent\Hosts.Bff.Blazor.PerComponent.Client\Hosts.Bff.Blazor.PerComponent.Client.csproj" />
<ProjectReference
Include="..\Blazor\PerComponent\Hosts.Bff.Blazor.PerComponent\Hosts.Bff.Blazor.PerComponent.csproj" />
<ProjectReference
Include="..\Blazor\WebAssembly\Hosts.Bff.Blazor.WebAssembly.Client\Hosts.Bff.Blazor.WebAssembly.Client.csproj" />
<ProjectReference
Include="..\Blazor\WebAssembly\Hosts.Bff.Blazor.WebAssembly\Hosts.Bff.Blazor.WebAssembly.csproj" />
<ProjectReference Include="..\Blazor\PerComponent\Hosts.Bff.Blazor.PerComponent.Client\Hosts.Bff.Blazor.PerComponent.Client.csproj" />
<ProjectReference Include="..\Blazor\PerComponent\Hosts.Bff.Blazor.PerComponent\Hosts.Bff.Blazor.PerComponent.csproj" />
<ProjectReference Include="..\Blazor\WebAssembly\Hosts.Bff.Blazor.WebAssembly.Client\Hosts.Bff.Blazor.WebAssembly.Client.csproj" />
<ProjectReference Include="..\Blazor\WebAssembly\Hosts.Bff.Blazor.WebAssembly\Hosts.Bff.Blazor.WebAssembly.csproj" />
<ProjectReference Include="..\Hosts.IdentityServer\Hosts.IdentityServer.csproj" />


<ProjectReference Include="..\..\templates\src\BffLocalApi\BffLocalApi.csproj" />
<ProjectReference Include="..\..\templates\src\BffRemoteApi\BffRemoteApi.csproj" />
<ProjectReference
Include="..\..\templates\src\BffBlazorAutoRenderMode\BffBlazorAutoRenderMode\BffBlazorAutoRenderMode.csproj" />
<ProjectReference Include="..\..\templates\src\BffBlazorAutoRenderMode\BffBlazorAutoRenderMode\BffBlazorAutoRenderMode.csproj" />

</ItemGroup>

Expand Down
16 changes: 15 additions & 1 deletion bff/hosts/Hosts.AppHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@
.WithAwaitedReference(api)
;

var bffMulti = builder.AddProject<Projects.Hosts_Bff_MultiFrontend>(AppHostServices.BffMultiFrontend)
.WithExternalHttpEndpoints()
.WithUrl("https://app1.localhost:5005", "https://app1.localhost:5005")
.WithUrl("https://localhost:5005/with-path", "https://localhost/with-path")
.WithAwaitedReference(idServer)
.WithAwaitedReference(isolatedApi)
.WithAwaitedReference(api)
;


var bffEf = builder.AddProject<Projects.Hosts_Bff_EF>(AppHostServices.BffEf)
.WithExternalHttpEndpoints()
.WithAwaitedReference(idServer)
Expand Down Expand Up @@ -48,11 +58,13 @@

idServer
.WithReference(bff)
.WithReference(bffMulti)
.WithReference(bffEf)
.WithReference(bffBlazorPerComponent)
.WithReference(bffBlazorWebAssembly)
.WithReference(apiDPop)
.WithReference(bffDPop);
.WithReference(bffDPop)
;

builder.AddProject<BffLocalApi>(AppHostServices.TemplateBffLocal, launchProfileName: null)
.WithHttpsEndpoint(5300, name: "bff-local");
Expand All @@ -62,6 +74,8 @@

builder.AddProject<BffBlazorAutoRenderMode>(AppHostServices.TemplateBffBlazor);



builder.Build().Run();

public static class Extensions
Expand Down
2 changes: 1 addition & 1 deletion bff/hosts/Hosts.AppHost/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:17052;http://localhost:15279",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
Expand Down
20 changes: 11 additions & 9 deletions bff/hosts/Hosts.Bff.DPoP/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Security.Cryptography;
using System.Text.Json;
using Duende.AccessTokenManagement.OpenIdConnect;
using Duende.Bff;
using Duende.Bff.AccessTokenManagement;
using Duende.Bff.Yarp;
Expand Down Expand Up @@ -31,7 +32,7 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde
{
Path = "/yarp/user-token/{**catch-all}"
}
}.WithAccessToken(TokenType.User).WithAntiforgeryCheck(),
}.WithAccessToken(RequiredTokenType.User).WithAntiforgeryCheck(),
new RouteConfig()
{
RouteId = "client-token",
Expand All @@ -41,7 +42,7 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde
{
Path = "/yarp/client-token/{**catch-all}"
}
}.WithAccessToken(TokenType.Client).WithAntiforgeryCheck(),
}.WithAccessToken(RequiredTokenType.Client).WithAntiforgeryCheck(),
new RouteConfig()
{
RouteId = "user-or-client-token",
Expand All @@ -51,7 +52,7 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde
{
Path = "/yarp/user-or-client-token/{**catch-all}"
}
}.WithAccessToken(TokenType.UserOrClient).WithAntiforgeryCheck(),
}.WithAccessToken(RequiredTokenType.UserOrClient).WithAntiforgeryCheck(),
new RouteConfig()
{
RouteId = "anonymous",
Expand All @@ -61,7 +62,8 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde
{
Path = "/yarp/anonymous/{**catch-all}"
}
}.WithAntiforgeryCheck()
}
.WithAntiforgeryCheck()
},
new[]
{
Expand All @@ -83,7 +85,7 @@ public static WebApplication ConfigureServices(this WebApplicationBuilder builde
var jwkKey = JsonWebKeyConverter.ConvertFromSecurityKey(rsaKey);
jwkKey.Alg = "PS256";
var jwk = JsonSerializer.Serialize(jwkKey);
options.DPoPJsonWebKey = jwk;
options.DPoPJsonWebKey = DPoPProofKey.Parse(jwk);
})
.AddRemoteApis()
.AddServerSideSessions();
Expand Down Expand Up @@ -183,21 +185,21 @@ private static void MapRemoteUrls(IEndpointRouteBuilder app)
{
// On this path, we use a client credentials token
app.MapRemoteBffApiEndpoint("/api/client-token", "https://localhost:5011")
.RequireAccessToken(TokenType.Client);
.WithAccessToken(RequiredTokenType.Client);

// On this path, we use a user token if logged in, and fall back to a client credentials token if not
app.MapRemoteBffApiEndpoint("/api/user-or-client-token", "https://localhost:5011")
.RequireAccessToken(TokenType.UserOrClient);
.WithAccessToken(RequiredTokenType.UserOrClient);

// On this path, we make anonymous requests
app.MapRemoteBffApiEndpoint("/api/anonymous", "https://localhost:5011");

// On this path, we use the client token only if the user is logged in
app.MapRemoteBffApiEndpoint("/api/optional-user-token", "https://localhost:5011")
.WithOptionalUserAccessToken();
.WithAccessToken(RequiredTokenType.UserOrNone);

// On this path, we require the user token
app.MapRemoteBffApiEndpoint("/api/user-token", "https://localhost:5011")
.RequireAccessToken();
.WithAccessToken();
}
}
4 changes: 2 additions & 2 deletions bff/hosts/Hosts.Bff.DPoP/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
{
"profiles": {
"Bff.DPoP": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:5003",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
2 changes: 1 addition & 1 deletion bff/hosts/Hosts.Bff.EF/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public static WebApplication ConfigurePipeline(this WebApplication app)
// user or client access token will be attached in API call
// user access token will be managed automatically using the refresh token
app.MapRemoteBffApiEndpoint("/api", "https://localhost:5010")
.RequireAccessToken(TokenType.UserOrClient);
.WithAccessToken(RequiredTokenType.UserOrClient);

return app;
}
Expand Down
6 changes: 3 additions & 3 deletions bff/hosts/Hosts.Bff.EF/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
{
"profiles": {
"Bff.EntityFramework": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:5004",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
}
15 changes: 8 additions & 7 deletions bff/hosts/Hosts.Bff.InMemory/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Duende Software. All rights reserved.
// See LICENSE in the project root for license information.

using Duende.AccessTokenManagement.OpenIdConnect;
using Duende.Bff;
using Duende.Bff.AccessTokenManagement;
using Duende.Bff.Configuration;
Expand Down Expand Up @@ -128,34 +129,34 @@ public static WebApplication ConfigurePipeline(this WebApplication app)

// On this path, we use a client credentials token
app.MapRemoteBffApiEndpoint("/api/client-token", "https://localhost:5010")
.RequireAccessToken(TokenType.Client);
.WithAccessToken(RequiredTokenType.Client);

// On this path, we use a user token if logged in, and fall back to a client credentials token if not
app.MapRemoteBffApiEndpoint("/api/user-or-client-token", "https://localhost:5010")
.RequireAccessToken(TokenType.UserOrClient);
.WithAccessToken(RequiredTokenType.UserOrClient);

// On this path, we make anonymous requests
app.MapRemoteBffApiEndpoint("/api/anonymous", "https://localhost:5010");

// On this path, we use the client token only if the user is logged in
app.MapRemoteBffApiEndpoint("/api/optional-user-token", "https://localhost:5010")
.WithOptionalUserAccessToken();
.WithAccessToken(RequiredTokenType.UserOrNone);

// On this path, we require the user token
app.MapRemoteBffApiEndpoint("/api/user-token", "https://localhost:5010")
.RequireAccessToken();
.WithAccessToken();

// On this path, we perform token exchange to impersonate a different user
// before making the api request
app.MapRemoteBffApiEndpoint("/api/impersonation", "https://localhost:5010")
.RequireAccessToken()
.WithAccessToken()
.WithAccessTokenRetriever<ImpersonationAccessTokenRetriever>();

// On this path, we obtain an audience constrained token and invoke
// a different api that requires such a token
app.MapRemoteBffApiEndpoint("/api/audience-constrained", "https://localhost:5012")
.RequireAccessToken()
.WithUserAccessTokenParameter(new BffUserAccessTokenParameters(resource: "urn:isolated-api"));
.WithAccessToken()
.WithUserAccessTokenParameter(new BffUserAccessTokenParameters { Resource = Resource.Parse("urn:isolated-api") });

return app;
}
Expand Down
22 changes: 16 additions & 6 deletions bff/hosts/Hosts.Bff.InMemory/ImpersonationAccessTokenRetriever.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ namespace Bff;

public class ImpersonationAccessTokenRetriever(IAccessTokenRetriever inner) : IAccessTokenRetriever
{
public async Task<AccessTokenResult> GetAccessToken(AccessTokenRetrievalContext context)
public async Task<AccessTokenResult> GetAccessTokenAsync(AccessTokenRetrievalContext context, CancellationToken ct = default)
{
var result = await inner.GetAccessToken(context);
var result = await inner.GetAccessTokenAsync(context, ct);

if (result is BearerTokenResult bearerToken)
{
Expand All @@ -26,18 +26,28 @@ public async Task<AccessTokenResult> GetAccessToken(AccessTokenRetrievalContext

SubjectToken = bearerToken.AccessToken,
SubjectTokenType = OidcConstants.TokenTypeIdentifiers.AccessToken
});
}, cancellationToken: ct);
if (exchangeResponse.AccessToken is null)
{
return new NoAccessTokenReturnedError("Token exchanged failed. Access token is null");
return new AccessTokenRetrievalError
{
Error = "Token exchanged failed. Access token is null"
};
}

if (exchangeResponse.IsError)
{
return new AccessTokenRetrievalError($"Token exchanged failed: {exchangeResponse.ErrorDescription}");
return new AccessTokenRetrievalError
{
Error = exchangeResponse.Error ?? "Failed to get access token",
ErrorDescription = exchangeResponse.ErrorDescription
};
}

return new BearerTokenResult(exchangeResponse.AccessToken);
return new BearerTokenResult
{
AccessToken = AccessToken.Parse(exchangeResponse.AccessToken)
};
}

return result;
Expand Down
4 changes: 2 additions & 2 deletions bff/hosts/Hosts.Bff.InMemory/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
{
"profiles": {
"Bff": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:5002",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
Loading
Loading