Git Product home page Git Product logo

bff's People

Contributors

andersabel avatar arturdorochowicz avatar benmccallum avatar brockallen avatar damianh avatar darrenschwarz avatar jacksos avatar josephdecock avatar leastprivilege avatar pascalsenn avatar pdekkers avatar programatt avatar skoruba avatar stefannikolei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bff's Issues

Consider service in DI to process management endpoints

Rather than having the code in BffManagementEndoints as static methods, we might consider having these simply call a service in DI to do the processing (like we do for MapBackchannelLogout). This might make #3 easier as well.

Lack of UseBff() method in Duende.BFF 1.0.0-rc.1

Which version of Duende IdentityServer are you using?
Duende.BFF 1.0.0-rc.1

Which version of .NET are you using?
.NET 5.0.104

Describe the bug

Actually, I downloaded the release from version 1.0.0-rc.1. Tried to run it, and I have got the exception that we lack UseBff() in this release.

See this: https://github.com/DuendeSoftware/BFF/blob/1.0.0-rc.1/samples/Blazor/Server/Startup.cs#L86

Expected behavior

I expected when I downloaded the examples from Duende.BFF 1.0.0-rc.1, then it should work correctly.

To fix it

I added the UseBff() method as below

app.UseRouting();
app.UseBff(); // <= add this in
app.UseAuthentication();
app.UseAuthorization();

I hope you guys can update the release 1.0.0-rc.1 with that code to make another people can get starting without build errors. Thank you.

Claims not mapped when using cookies

Which version of Duende IdentityServer are you using?
5.2.1
Which version of .NET are you using?
.net 5
Describe the bug
Identity Server + BFF + Cookies + AspNetIdentity results in

[18:05:08 Information] Microsoft.AspNetCore.Authorization.DefaultAuthorizationService
Authorization failed. These requirements were not met:
ClaimsAuthorizationRequirement:Claim.Type=scope and Claim.Value is one of the following values: (myapi)

A clear and concise description of what the bug is.

To Reproduce

Steps to reproduce the behavior.

Expected behavior
To authorize users with correct scope
A clear and concise description of what you expected to happen.

Log output/exception with stacktrace

data

Additional context

in startup.cs

.AddOpenIdConnect("oidc", options =>
            {
...
                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Scope.Add("myapi");
                options.Scope.Add("offline_access");
 services.AddAuthorization(options =>
            {
                options.AddPolicy("MyApiScope", policy =>
                {
                    policy.RequireClaim("scope", "myapi");
                    ...
               }
        }
...
endpoints.MapControllers().RequireAuthorization("MyApiScope").AsBffApiEndpoint();

id server logs:


[18:05:07 Debug] Duende.IdentityServer.Validation.TokenValidator
Token validation success
{"ClientId": null, "ClientName": null, "ValidateLifetime": true, "AccessTokenType": "Jwt", "ExpectedScope": "openid", "TokenHandle": null, "JwtId": "C1B9ED46ACD5E6472DAD50CAF1E91D36", "Claims": {"iss": "https://localhost:5001", "nbf": 1625825107, "iat": 1625825107, "exp": 1625828707, "aud": "https://localhost:5001/resources", "scope": ["openid", "profile", "myapi", "offline_access"], "amr": "pwd", "client_id": "test", "sub": "89fcb5a9-2cdb-490b-838c-37290534a7be", "auth_time": 1625825106, "idp": "local", "sid": "B827C8AA731BA325A5054A486235D455", "jti": "C1B9ED46ACD5E6472DAD50CAF1E91D36"}, "$type": "TokenValidationLog"}

[18:05:07 Debug] Duende.IdentityServer.ResponseHandling.UserInfoResponseGenerator
Creating userinfo response

[18:05:07 Debug] Duende.IdentityServer.ResponseHandling.UserInfoResponseGenerator
Scopes in access token: openid profile myapi offline_access

[18:05:07 Debug] Duende.IdentityServer.EntityFramework.Stores.ResourceStore
Found ["profile", "openid"] identity scopes in database

[18:05:07 Debug] Duende.IdentityServer.ResponseHandling.UserInfoResponseGenerator
Requested claim types: profile preferred_username nickname middle_name given_name family_name name picture website gender birthdate zoneinfo locale updated_at sub

[18:05:07 Information] Duende.IdentityServer.ResponseHandling.UserInfoResponseGenerator
Profile service returned the following claim types: sub name given_name family_name website preferred_username

[18:05:07 Debug] Duende.IdentityServer.Endpoints.UserInfoEndpoint
End userinfo request


InvalidOperationException: Session id claim value does not match ticket in database for key

Which version of Duende IdentityServer are you using?
1.1.0-preview.2
Which version of .NET are you using?
Dotnet 6
Describe the bug
Login fails the second time against IdentityServer after clearing IdentityServer cookies.

To Reproduce

  • Setup the BFF to use OIDC (authorization_code) against IdentityServer (Version 6)
  • Trigger the login flow via the BFF (/login?state=someStateHere)
  • Login via IdentityServer (We are using local users)
  • Get redirected to your client application - everything works.
  • Remove the IdentityServer cookies from your browser.
  • Trigger the login flow again
  • Login via IdentityServer
  • You will now get the following exception on the BFF host

InvalidOperationException: Session id claim value does not match ticket in database for key `046EFCF5449408B36A8CF1C6CE530D8A9F07E7FD708AF9536D547D738383C0E6`
    Duende.Bff.ServerSideTicketStore.RenewAsync(string key, AuthenticationTicket ticket) in ServerSideTicketStore.cs
    Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler.HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
    Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
    Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler<TOptions>.HandleRequestAsync()
    Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
    Duende.Bff.Endpoints.BffMiddleware.Invoke(HttpContext context) in BffMiddleware.cs
    Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Expected behavior
I get logged in.

Claims received in the BFF:
bff-exception

And this is how the UserSessions table row looks like:

4,my-client,2021-12-16 15:00:00.000000 +00:00,2021-12-30 15:00:00.000000 +00:00,"{""Version"":1,""Payload"":""CfDJ8LTdhSWxBi1Jtx1WRxlftZTky2-KQPz6oFq7ogdlY_lIOLlCrBRIjf5WoN0yYur6IhK0VhKCSDvO_92TGvQe211Wa0f9tSzJ9Pgu2Kt_pBNKhLh_KEz-022Z0yc_sBkrG_FLuJ02Ct_9U2RY4FHG58luJNE1T86AgyiXpuB5vtBnVEDhtSwP4L0rbEBD6K-rv0JQIjP4qg9E9bNGqC_ZL8Xl5rPnWk2tIKN8zneXREUASAJdYI8RMs5HWtrDNjGIHn0Ulx-S517HyfTrQ9FVgBP5EF2BILB2_zu60x-PyY9C2lWTahI4cPBepBJIvaoNjFt0y4XLt4GJc_lj7soRitjKBM2lNTZAKcQdBxQe_peMlsUQcRMP6G4IVBGGkfPAcK1Cg26rmIWqg7c5lNSDGA05PrDghEZwsl6LgF9guHB6KYugwLX5UuNzGl4u0_398KqMRowCCroRxb9vTzk7xM4qnzDWtf-VqRHCpSWxy3_GDhIiswzfS7g4eRowM9stkvp_btpPp5XXqQrXcyjgAJBJFgpZoi0uEBH2g3uzuQkk8CqFEi8X2TDMtYal-3yy8xBRCP_lo62bLJkIoD9lcjvP0HJO1HQ_QO6IG8gaoUuZVHwMN88iLMH8YmDxGVGVQB8YMgRRO4SpGxVR4PMax-FkMGDnSASXolSpft83J4Bx2AxsDlzPoJMxPQyeGibRAqtNXD7Mes12RRx4EES8bNts9HKm8euaDcGddRGIu7Nc3ZYbi86EiO1qY4FMOe0OU6mGQhLhWTBiQF5wcsuiGbxIoOF95iBbfLtdomeKhOxpD9ifGa9SRIgid5XCyGAJv-k1xPOPF6VSOs-hUF-Gm1fW6_U0mAq9eBfsu3fIKNIft00uL4tfYTs_ATd-7yTG5ZWs-jyr18U7qfeMy1_Vwu7q9Um_vO0TwIOaxGr54VWvBVmfVIHovQcH7bmwuNFU4MmRuAGNHLIXRppx_S10y7RqFqOSUhIXiO3jj2Pjq1iq1HrmXb18kS5slkr0bW8NaiA3p26xgtR4MdCo29ai9HbTLIWAti4lMwRfLgASWxYl8Pg5yZcL5D2tUv5k7tNbifREGgBvD1T_8a0FmYL_XnOBhpc9vIX4Rum4Y2rA1WD3EXDo4uNrGMvud5_CH4XYEkatrdhNes3sq6wCTqVfSAg11LX3RadCLg62i6Bkyzub07ei1OS3B_UQi45Jo3zdWOk4L7trBC_RMp5fOG3AJS-3ANJC2nnjDU4AdHoxQ-aKghl5vze6O_wuRGG4zp5DdTRcepWVh1Z02g5nP_PtO2kC5J0HSolDeN3kOXG3RAcgjIygoUKBJ_uDeEayltbGh73huQvWEAf1lMRDWbqI_W-oXvx_hPakKP6ZSmUw_JrP7tzZf9aAwXpOnOy4QERKlvbtv8tfC4lGIhcuxdp1sDEIAYNyjd26S5Ucri62SH56YZJTuxLPzOO2g_RwgWszx264Ex8claYrU4XX0S6ljp6HJztwWYQg44D20FX-aVsgCm40hlZfCpPVfTNO7z7NBzrDBTzA-u3NdF_T1h_kbw7125AlWWaG3Q9QwlElDHXTYsFRe2-hCXaoXsLoDHbpM2LDZNESd69KYrPznunuqYtj3ElGgqDoVJ6fbGK1ngj75rcV9VKHXsYr02xhnutondFUDw18HeVKU35FgsZdD8LYa3OiyxSPMf3mEGim2YuUxgBwKuHhL924MoWEe8x6GMuN4FErtraOlhU1OBoUSRQtv1wO_Rl0eWLdjP3KZPyB2yafu5opYgY7QjP9PU7ZPCecbM8jmQ4CDr6lqWmlMdBp_-ojGh0JB5pF3kn-RRH6kWG9dA2hi_RIt7H-Qo0QTKcixZbEWvKw5Mg0ePKoLCCXp4lG-57OM9ZOBQEAqCwXWjHtPc6-eLBXkSlB_MSmX9KTDAtTP9W23K3LLSHT3m5QQaXOXhXM7XKA5xjezlSk9fGeCfQO2PBYwR4ms0Za42O5UajVcuYw4hVUmtoKdeskg7H7WRfCIgRDcnpNtzSiJU6mvsLgoqAnstl_qTFFC-ol-zwVAZNgnPKc8l9kgIy8nA8FFxRzL6_So0SGs_XkvaW4knlKu6kgDjBqmEhmej7SlEHIm8Wao-w3KVL0-1iG8B6O1zF1W0Fa0qaVTIoG6ltW6RMrdxgqT5bbmm-9iUO-ExKYWVVYnSmLKZ9cRiP7AWl8cUekyBNYhILp1RKUoqN_sPYHb_PSKkaJbPUHJv1trNx-L1a3OzFCyZErv_O0e0LL3E7WLnLKDNXkkWzR8GjDZvMZwCS3fmApWh74X5W3gZRbZLqlwcN9kfEzx4Ik0my_M-i301L9AtOoFycPz5ETgpy6Yrrw0Hh-zcCh9UDM2ZgvYxEqwqZmxvswCGujV24jnWh-nh7EL8SpcAKt8LMp0rM3408ao_yBmuyj5YOfhAftGZLToHMawnWeQn0WXLdHlF0RCANDZ9lFxfcJTRxrVPLjlWtg6hUHjASyGZ_fUCTEMFRUi2G8120E9ugMY4_-k_B79TCzbeEQZYLeTtdfeCc3sEVeurIZJOqBOrdeTOeMcC8F3CNFAeIMaIbi-ZGNQ3fN7uhtOWJ6awtAytn-58upX0xfW1b_ndMNgAjtTmBXwVK0SWEAKHj6G3gkYGdf1l_LcomJloKJbE81FL3y0vVv8Teh7rJlWOaOuwjFT-2p7Bl0jWgPghqqf_lqv0Abni4JOJtcW7mfYGGcmW2l04wv8mtKTjFQH7_tYZY6llkvFkx50XPcLwRb4Yg7p543bdPJg42h7uKdY88uyxY8k5I6_mzFJRAwefwWc217md4J6vqaOqEoUrJww1bKqFF14X1ffRMziKCH1mcz1gJ5frul9goLXttJsJZIJH8YPezf_tgCKPejKwvCpBTzSZXQhuKLmHB8EhegcMjrE1T6xy48kKZlGbt3hIBfj1rlLxXy5zWQXKRMj0mERab7IBl-lMxQclcNcv_uAEl2d6v9aKh9RWvSsGj8Tpoiv_O5yXqezUfnvbeXWcOsAJgh9ZxZhl0gMINKVpwajMas3Cl2IZYuNyqrPLGpNhyusJPQ1Ga8oqALJ9TY9NRrGUP-F_iAjKI5I9xzhGuSHdDIyUefPNPxFkMofT4SYh_8kUKeHKFhXYV7pwZZQnMpPxwv7EccISWpEbG6JDD61JOXWNgdxUSl_X0epy-BGPMJUapMqHnlYm7lgCKDhxHXco39JcAthzvp1Gxegvs931ls9DcNJs6SNg1B6Sn-B9KEAKZGBksdbeyGYX0FegrfbS7boKjmB-9E-_uZ3UoV82HTGn9VJRHWSnlf4Rvu0rO_PlUcu9lQ8xuz22zaYZyyxsMF63PhQm_JVfFR3cqWGdsj0KPbY1E94H0oWNLVZeSVK-IZlGrWhnEAn3IblzwaAC4WTmjMOSN_A8HHHnlehVGaNP6XfNfzDkgOv9YH9mYKNCmig4R-SI1l2h6afwSeBOOhqp31Ct8Z4gigxu2xfngJa-C90uoN4e4foNm1Vi_029sEWir2t145swgsxTu32Q7Xl8BAPxtbJvszOtWu9erUlqivp-GO1BCq1UPc6ltViglrn786zPcbDwohbe_YNK36KTSWWhBlbcTCHd6-VpXtMreo7iG6qwW5oZsH6BzFiFSHdZ8cFFten0Jqenv2BBt1xk-q4zA05yxBZbTFQozUaLnShUmYjh3xrZCOPjH5fEI2BfWoq2IwqnRcvyrUZWl3bly_XWAgNoe9kimFlGiqoBFyGaE5Qf48LOFBtoDgGCcNZS_ZM7b9ChInaMqYIml6DF9f35oV1aDfxh7vwNOjhNFvf3NuI48e7UtwJKl9GmUA_NOQeC0T5rsm8MF__kPOb2wfOR807jQ1myk26ZCpY-YuEQ8I4EiLfVeSuFUNReShcDgFKupTbBmY-rTddphbICkDD1NR3Xu0g4JkxKQ-6_06QWb2TRSp_VVW134EpAN88XYVrf8IvHZ5iikFYJI8Ev44Iemt98GXVEN6Ioc1Nu627paqzV3bNsVrY36s5iqPpga0YIbAY_tJCtJGi3BStWl0dHRb4bq4D1hPrybv4OA5cbrnoB5w4mk6jee4cCUmylfXhzUtuVpGha5d5Khu4uY9vHD0HhEz73PpwAABbxdPX190I3GG0Wo-pRViA-M6-UmIchDKD4DqhdK7tiCQ8OJMBPMBxkdcl67HJsd-HggRsUvXfSGNgX-Ldo68pG9Uj_W4Tb7EBIypMEZpO5odpS67FfcsEZQriIgEbrFv2EHkAqUJAp0x1Dl-uyp0N9Zdz70RwB9rCwzfTxk09ZaSYiBArQgisC3hnrEph_MJjnnm1eRlI1qZ9qmMSxDghHHOav3Y5Y-V-epPwioj3n5Gw8mZq_CFc33N0Xq-xnznOZJz41gfc3-BkfeVKugDaB-Cekl0Q693c187lIkAz4kD63Qj0-zpQVMAwUVFPhvVXyHMK48bJJtgWwqhbchDBfNiQPgTFqZo7zL1sDLkxOu1_MkWFoeRmXm9z5rAP0-WTe0HMww3dzLzebrmcQtJhQ""}",046EFCF5449408B36A8CF1C6CE530D8A9F07E7FD708AF9536D547D738383C0E6,8d212e57-75d1-4bd6-9890-09d39178159b,0AE42A193FC1E997196A8D675078A833,2021-12-16 15:00:00.000000 +00:00

Revoke refresh token on signout

  • add feature flag on options
  • handle OnSigningOut event and call HttpContext.RevokeUserRefreshTokenAsync
  • call revocation endpoint on back-channel handler via ITokenEndpointService

Blazor Server returning 401

Which version of Duende IdentityServer are you using? 1.0.0-rc.3

Which version of .NET are you using? .NET 6 RC1

Describe the bug
image

A clear and concise description of what the bug is.
I have a Blazor Hosted App and configured BFF as per the documentation. See below a piece of Configure method from Startup.cs

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBffManagementEndpoints();
                endpoints.MapRemoteBffApiEndpoint("/api", "https://localhost:5010").RequireAccessToken(TokenType.UserOrClient);
                endpoints.MapControllers().RequireAuthorization().AsBffApiEndpoint();

                endpoints.MapRazorPages();
                endpoints.MapFallbackToFile("index.html");
            });

When the app is starts never finishes loading, then I checked the Dev Console and got the error above.

Expected behavior
It is my understanding that any API in Blazor Server will required authorization, which is a problem, because there is an API I need to call anonymously from Blazor Client -Program.cs- in order to get a configuration value before the app starts. Is there any way I can exclude that API from being protected?

Util.IsLocalUrl should not allow "~/"

The code in Util.IsLocalUrl is clearly borrowed from MVC. The thing is that various parts of MVC recognize and resolve "~/" in url strings. But in BFF the values that pass this are used in AuthenticationProperties.RedirectUri and the ultimate consumer of this is the OIDC authentication middleware which has no special processing for "~/".

I think the following fragment should be removed and return false.

// Allows "~/" or "~/foo" but not "~//" or "~/\".
case '~' when url.Length > 1 && url[1] == '/':
{
// url is exactly "~/"
if (url.Length == 2)
{
return true;
}
// url doesn't start with "~//" or "~/\"
if (url[2] != '/' && url[2] != '\\')
{
return !HasControlCharacter(url.AsSpan(2));
}
return false;
}

Antiforgery token validation failed

I have a Blazor app and for some reason there are 2 endpoinst failing with a 401 and when I checked the event logs I see this.

Category: Duende.Bff.Endpoints.BffMiddleware
EventId: 2
SpanId: 6d3fc7c7594838cc
TraceId: b9e4542533b256b89b48a98ea9fad13e
ParentId: 0000000000000000
RequestId: 80000020-0002-c800-b63f-84710c7967bb
RequestPath: /myapipath/

Anti-forgery validation failed. local path: '/myapipath/'

In Startup.cs I have this

                services.AddAuthentication(options =>
                {
                     //hidden for brevity
                })
                .AddCookie(openIdSettings.OpenIdBrowserUXDefaultScheme, options =>
                {
                    options.Cookie.Name = "__Host_Blazor";
                    options.Cookie.SameSite = SameSiteMode.Strict;
                })
                .AddOpenIdConnect(openIdSettings.OpenIdBrowserUXDefaultChallengeScheme, options =>
                {
                     //hidden for brevity
                });

Any suggestion as to how this can be fixed?

Thanks beforehand.

Read value of cookie __Host_Blazor

This is more a question than a bug.

I need to read the value of the cookie, but for some reason it keeps returning the same hashed value.

var cookiePlainText = HttpUtility.UrlDecode(context.Request.Cookies["__Host_Blazor"]);

Is there any way I can get the plain text for that cookie?

Option to disable anti-forgery check when using reverse proxy

The anti-forgery check that is applied when using YARP makes testing and debugging API's during development somewhat cumbersome. A simple option to disable this would be very helpful. Something along the lines of:

builder.Services.AddBff()
                .AddServerSideSessions();
                .AddReverseProxy()
                .AddTransforms<AccessTokenTransformProvider>()
                .WithAccessToken(...)
                .WithAntiforgeryCheck(false)

BFFMiddleWare calls Add on HttpContext.Items rather than TryAdd causing error

Which version of Duende IdentityServer are you using?
Version 1.1.3 of Duende.BFF and Duende.BFF.Yarp
Which version of .NET are you using?
.Net 6
Describe the bug
BFFMiddleware does not check to see if it has already been registered and calls Add on the Items dictionary which throws an error:

Should use context.Items.TryAdd rather than context.Items.Add or simply set it via the index.

To Reproduce

Call app.UseBff more than once at startup.

Expected behavior
The BFFMiddleware should only be registered once and should check if it has already been registered.

Log output/exception with stacktrace

System.ArgumentException: An item with the same key has already been added. Key: Duende.Bff.BffMiddlewareMarker
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at Microsoft.AspNetCore.Http.ItemsDictionary.System.Collections.Generic.IDictionary<System.Object,System.Object>.Add(Object key, Object value)
   at Duende.Bff.Endpoints.BffMiddleware.Invoke(HttpContext context) in /_/src/Duende.Bff/BffMiddleware.cs:line 43
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at OrchardCore.Diagnostics.DiagnosticsStartupFilter.<>c__DisplayClass3_0.<<Configure>b__1>d.MoveNext()
`

Additional context
Application startup may be reentrant or UseBff may be called multiple times by mistake but it shouldn't crash the app. Even the AuthorizationMiddleware uses something similar:

                context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = AuthorizationMiddlewareWithEndpointInvokedValue;

Add any other context about the problem here.

BffApiAttribute action level

Which version of Duende IdentityServer are you using?
5.2.2 / Bff rc3

Which version of .NET are you using?
Net5.0

Describe the bug
[BffApi] Cannot be applied to Actions

A clear and concise description of what the bug is.
It would be helpful if we can apply the attribute to Actions not on the ApiController, as some will have Allow Anonymous and the antiforgery will reject those requests

PathBase is ignored in bff:logout_url returned from /bff/user endpoint

Which version of Duende IdentityServer are you using?

  • Duende.IdentityServer: 5.2.3
  • Duende.BFF: 1.0.0

Which version of .NET are you using?

  • 6.0

Describe the bug
BFF-based ASP.NET Core WebApi application with UsePathBase set responds to the user endpoint with the bff:logout_url property ignoring the PathBase.

To Reproduce

  • Create project from the "Duende BFF with JavaScript" template.
  • In Startup.cs modify Startup.Configure method by adding as the first statement
app.UsePathBase("/api");
  • Run application, login and request /api/bff/user
  • Look at the response's array element with type=bff:logout_url
  • The result is
{
  "type": "bff:logout_url",
  "value": "/bff/logout?sid=E18EF260B13B4E494C0CE1D449EFAFCC"
},

Expected behavior

{
  "type": "bff:logout_url",
  "value": "/api/bff/logout?sid=E18EF260B13B4E494C0CE1D449EFAFCC"
},

Additional context

In production environment the BFF server is running behind a reverse proxy, so the PathBase is setup to properly route the requests from the SPA application to the BFF server. The logout URL is though returned without the PathBase and could not be properly routed. For example, here is the proxy configuration for dev server setup using http-proxy-middleware:

  app.use(
    '/api',
    createProxyMiddleware({
      target: 'https://localhost:5001',
      secure: false,
      headers: {"Connection": "keep-alive"}
    })
  );

400 status code when using AutoValidateAntiforgeryTokenAttribute

I want to exclude some endpoints from being checked for antiforgery (GET only). Hence, I'm using the following,

services.AddControllers(options => 
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});

According to the AutoValidateAntiforgeryTokenAuthorizationFilter implementation, GET will be excluded from checking antiforgery. However, after I'm logged on, the following request is a POST and I get a 400. Somehow, when I remove the above filter then app works as usual. The reason I needed to add that filter was because AsBffApiEndpoint() is requiring antiforgery header in all endpoints, and I need some of them to be bypassed.

Also, in Blazor6 sample code I see MapRemoteBffApiEndpoint(...).RequireAccessToken(TokenType.UserOrClient) is not being used. Is this the new pattern?

GetLogoutContextAsync(logoutId) returning PostLogoutRedirectUri null when session is expired

Which version of Duende IdentityServer are you using?
6.0.0-preview.2

Which version of .NET are you using?
.NET 6 GA

Describe the bug

This method var logout = await this.interaction.GetLogoutContextAsync(logoutId); not always return yield the PostLogoutRedirectUri value I expect. For some reason while the session is active, if I click Logout in the Client I'm redirected to the IdentityServer logout page and I do get the appropriate value. However, when the session is expired due to inactivity -set in the cookie- and I'm sent to the IdentityServer logout page this value comes null.

IEndpointRouteBuilder does not contain a definition for MapRemoteBffApiEndpoint

I just recently upgraded my Blazor Server Duende.BFF package from rc3 to v1 and now the build cannot be completed because of the following error. IntelliSense indeed does not show it.

'IEndpointRouteBuilder' does not contain a definition for 'MapRemoteBffApiEndpoint' and no accessible extension method 'MapRemoteBffApiEndpoint' accepting a first argument of type 'IEndpointRouteBuilder' could be found (are you missing a using directive or an assembly reference?)

The package I upgrade to was this and I was looking for release notes but the page is empty.

Threw error: Fetching user failed. System.Text.Json.JsonException: The JSON value could not be converted to Blazor.Client.Services.HostAuthenticationStateProvider+ClaimRecord

Which version of Duende IdentityServer are you using?
Duende.BFF - 1.0.0-rc.1

Which version of .NET are you using?
.NET 5.0.104

Describe the bug

After setup the Blazer WASM project with 3 projects in place (Blazor.Shared, Blazor.Server, and Blazor.Client). I run the app at https://localhost:5002. I can log in via re-direct to https://localhost:5001 to use bob/bob to log in successfully in the system. Then it does a redirect back into https://localhost:5002. But on this page, I have got the exception:

Fetching user failed. System.Text.Json.JsonException: The JSON value could not be converted to Blazor.Client.Services.HostAuthenticationStateProvider+ClaimRecord

Expected behavior

I expect that after login, the Blazor.Client.Services.HostAuthenticationStateProvider+ClaimRecord can access into the claims and extract it as well as display it correctly in MainLayout.razor, that's mean

<AuthorizeView>
    <Authorized>
        <strong>Hello, @context.User.Identity?.Name!</strong>
        <a href="@context.User.FindFirst("bff:logout_url")?.Value">Log out</a>
    </Authorized>
    <NotAuthorized>
        <a href="bff/login">Log in</a>
    </NotAuthorized>
</AuthorizeView>

Log output/exception with stack trace

I pressed F12 on the browser and see the output at the console tab:

blazor.webassembly.js:1 warn: Blazor.Client.Services.HostAuthenticationStateProvider[0]
      Fetching user failed.
System.Text.Json.JsonException: The JSON value could not be converted to Blazor.Client.Services.HostAuthenticationStateProvider+ClaimRecord. Path: $[9].value | LineNumber: 0 | BytePositionInLine: 439.
 ---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
   at System.Text.Json.Utf8JsonReader.GetString()
   at System.Text.Json.Serialization.Converters.StringConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverter`1[[System.String, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, String& value)
   at System.Text.Json.Serialization.Converters.SmallObjectWithParameterizedConstructorConverter`5[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryRead[String](ReadStack& state, Utf8JsonReader& reader, JsonParameterInfo jsonParameterInfo, String& arg)
   at System.Text.Json.Serialization.Converters.SmallObjectWithParameterizedConstructorConverter`5[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.String, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadAndCacheConstructorArgument(ReadStack& state, Utf8JsonReader& reader, JsonParameterInfo jsonParameterInfo)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].ReadConstructorArgumentsWithContinuation(ReadStack& state, Utf8JsonReader& reader, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, ClaimRecord& value)
   at System.Text.Json.Serialization.JsonConverter`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, ClaimRecord& value)
   at System.Text.Json.Serialization.Converters.IEnumerableDefaultConverter`2[[System.Collections.Generic.List`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, List`1& value)
   at System.Text.Json.Serialization.JsonConverter`1[[System.Collections.Generic.List`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, List`1& value)
   at System.Text.Json.Serialization.JsonConverter`1[[System.Collections.Generic.List`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   --- End of inner exception stack trace ---
   at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
   at System.Text.Json.Serialization.JsonConverter`1[[System.Collections.Generic.List`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadCore[List`1](JsonConverter jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadCore[List`1](JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& state, JsonConverter converterBase)
   at System.Text.Json.JsonSerializer.<ReadAsync>d__20`1[[System.Collections.Generic.List`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
   at System.Net.Http.Json.HttpContentJsonExtensions.<ReadFromJsonAsyncCore>d__3`1[[System.Collections.Generic.List`1[[Blazor.Client.Services.HostAuthenticationStateProvider.ClaimRecord, Blazor.Client, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
   at Blazor.Client.Services.HostAuthenticationStateProvider.FetchUser() in D:\github\clean-architecture-dotnet\samples\WebBlazor\Client\Services\HostAuthenticationStateProvider.cs:line 70

Dirty fix it

I look at the Network tab on the browser:

image

After looked around in the source code of this repo and found out the code for it at https://github.com/DuendeSoftware/BFF/blob/1.0.0-rc.1/src/Duende.Bff/Endpoints/DefaultUserService.cs#L112

I did a dirty hack in my project by overriding the DefaultUserService as

services.AddBff()
	.AddServerSideSessions();

services.Replace(ServiceDescriptor.Transient<IUserService, MyDefaultUserService>());

And in the MyDefaultUserService.cs, I converted this expiresInSeconds into String type

//...

var expiresInSeconds =
    authenticateResult.Properties.ExpiresUtc.Value.Subtract(DateTimeOffset.UtcNow).TotalSeconds;
claims.Add(new ClaimRecord(
    Constants.ClaimTypes.SessionExpiresIn,
    Math.Round(expiresInSeconds).ToString(CultureInfo.InvariantCulture)));
//...

Finally, I run the code again with this little hack, then everything runs well.

image

Looks at all the claims values should be a string type on the Blazor client-side.
Let me know if that is a bug or not. And if that is a bug, I'm happy to do a fix for this repository. Thank you!

Issue with EFCore session store implementation when using multiple DBContext

Duende IdentityServer V5
Donnet 6 Preview 4

Below code is added to the StartUp class for EFCore based session store implementation.

services.AddBff()
    .AddEntityFrameworkServerSideSessions(options=> 
    {
        options.UseSqlServer(cn);        
    });

When the user tries to log in below exception is thrown:

InvalidOperationException: The DbContextOptions passed to the SessionDbContext constructor must be a DbContextOptions<SessionDbContext>. When registering multiple DbContext types, make sure that the constructor for each context type has a DbContextOptions<TContext> parameter rather than a non-generic DbContextOptions parameter.

Note:
Another DbContext (ApplicationDbContext) also registered in the same class.

Possible solution:
Changing SessionDbContext the parameter to a generic parameter.

       public SessionDbContext(DbContextOptions<SessionDbContext> options) : base(options)
        {
        }

DbUpdateConcurrencyException when deleting expired session from store

Which version of Duende IdentityServer are you using?

  • Duende.BFF 1.1.0-preview.1
  • Duende.BFF.EntityFramework 1.1.0-preview.1
  • Duende.BFF.Yarp 1.1.0-preview.1

Which version of .NET are you using?
.NET 6.0

Describe the bug
Concurrent/parallel requests with a cookie associated with an expired authentication ticket will result in one request removing the expired session from the store and the other throwing a DbUpdateConcurrencyException. This generates a server error rather than 401 Unauthorized for the caller.

To Reproduce
The same behaviour can be reproduced in a contrived test harness that:

  • Creates a session in the database
  • Makes parallel calls to DeleteUserSessionAsync via separate DI scopes

Repro in test here.

Expected behaviour
No exception thrown

Log output/exception with stacktrace

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ThrowAggregateUpdateConcurrencyException(Int32 commandIndex, Int32 expectedRowsAffected, Int32 rowsAffected)
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagationAsync(Int32 commandIndex, RelationalDataReader reader, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader reader, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(StateManager stateManager, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Duende.Bff.EntityFramework.UserSessionStore.DeleteUserSessionAsync(String key, CancellationToken cancellationToken) in /_/src/Duende.Bff.EntityFramework/UserSessionStore.cs:line 65
   at Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler.ReadCookieTicket()
   at Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

Additional context
We see the exceptions regularly, but at low rates (circa 1% of total traffic) in a real world environment

Logout notification support

  • ping endpoint for JS to replace check_session (that won't slide cookie?)
  • or signalr callback w/ JS library to get notified of backchannel logouts

Duplicate server side session id when manually deleting cookies on application and issue login

Which version of Duende IdentityServer are you using?
5.2.2 / BFF rc3

Which version of .NET are you using?
Net 5.0

Describe the bug
If the user is successfully logged in and redirected to main application then the user clears the cookies (on application only) and sign in again. Identity server signs in the user as cookie is available on identity server, then when redirected to application to store the userSession the store throws unique exception

An unhandled exception occurred while processing the request.
SqlException: Cannot insert duplicate key row in object 'dbo.UserSessions' with unique index 'IX_UserSessions_ApplicationName_SessionId'. The duplicate key value is

To Reproduce
services.AddBff(options =>
{
})
.AddEntityFrameworkServerSideSessions(options =>
{
options.UseSqlServer(sqlIdentityConnectionString);
});

Steps to reproduce the behavior.
If the user is successfully logged in and redirected to main application then the user clears the cookies (on application only) and sign in again. Identity server signs in the user as cookie is available on identity server, then when redirected to application to store the userSession the store throws unique exception

Expected behavior

A clear and concise description of what you expected to happen.
It seems dotnet is trying to store the same ticket with same sessionId

Additional context

Add any other context about the problem here.

Look into: RequireAntiForgeryCheck: false

With this fix the RequireAntiForgeryCheck: false stopped working for the local API when set at the controller action level attribute like this:

// GET productapi/v1/image/5
[BffApi(false)]
[HttpGet("{id:length(24)}")]
public Task<ActionResult> Get(string id) => (

It now requires the anti-forgery header for this action and returns 401. If rollback to 1.2.1 it works as expected.

Originally posted by @dgrozenok in #102 (comment)

401 when token expired and Reason comes blank

Hi Brock,

In my Blazor Server project in Startup.cs I set the cookie to expire after 4 min. Once passed that time, I interact with a component that needs to talk to the server and I see nothing is happening. After opening the dev tools I realize there is a 401 result. I added a breakpoint in the component to see the reason for the 401 hoping it'll say something like token expired or so. To my surprise the Reason property is empty. Most importantly, if the token is expired shouldn't bff middleware sent me back to bff/login or do I have to manually set that?

Thanks in advance

Anonymous access not works

Duende IdentityServer4
Donnet 6 Preview 4

Attribute [AllowAnonymous] not works in the controller and 401 error is returned instead.

  1. Created a Blazor Wasm Hosted App
  2. Configure the BFF (Server App/ ClientApp)
  3. Configure IdentityServer on the same app (Server App)
  4. Create an MVC controller and decorate it with [AllowAnonymous]
  5. Call the controller

Result:
401 Unauthorized exception when calling the MVC controller

Observation:
When the below line is commented out from the Startup class the controller can be accessed anonymously.
app.UseBff();

BFF Blazor - login and remember me

Version:
Duende IdentityServer 5.2.2
Identity server project on .NET 6.0 with Entity Framework and ASP.NET Identity (with 2 factor authentication).

BBF Blazor sample:
When you choose the option 'Remember me' while logging in, you will be redirected back to the client and the claims will be shown. However, when you restart the application again, the login button will appear again.

In the browser console you will see the following result when starting the application:
Sending HTTP request GET https://localhost:5002/bff/user
Failed to load resource: the server responded with a status of 401 ()

After you click on login again, the following error message appears:
SqlException: Cannot insert duplicate key row in object 'dbo.UserSessions' with unique index 'IX_UserSessions_ApplicationName_SessionId'.
The duplicate key value is (Blazor.Server, BC12C0A9300B154697BF1F184E34AC0E).

When you now empty the UserSessions table and restart the application, you will still see the login button, but after you have clicked on it, you will immediately see your claims without logging in again.

In the identity server account options the AllowRememberLogin property is set to true.

Expected result:
When you choose the option 'Remember me' during login and you restart the application, the user would be immediately retrieved and the claims displayed.

BFF Can't user local API and Remote API in the same project

Hello,
I am using the BFF .net 6 React sample here https://github.com/DuendeSoftware/Samples/blob/main/IdentityServer/v6/BFF/ReactBffSample/src/FrontendHost/Program.cs
Local API and Remote API each one works fine when enabled alone
But when i want to use both (same endpoint i want them to be redirected to my local controller, and other just a proxy to other api ) it dont work, all routes are redirected to local controller or not found error.

               // local APIs
                endpoints.MapControllers()
                    .RequireAuthorization()
                    .AsBffApiEndpoint();

                // login, logout, user, backchannel logout...
                endpoints.MapBffManagementEndpoints();
                
                // proxy endpoint for cross-site APIs
                // all calls to /api/* will be forwarded to the remote API
                // user or client access token will be attached in API call
                // user access token will be managed automatically using the refresh token
                endpoints.MapRemoteBffApiEndpoint("/api", "https://localhost:5010")
                    .RequireAccessToken(TokenType.UserOrClient);

thank you for your help.

Feature Request: Option to maintain claim type names for standard claim types on bff user endpoint

The issue

We are implementing BFF into a large existing project and want to minimize the changes to our clients. Currently we have a number of claims returned such as "given_name", "email" and others. When implementing the BFF solution the user endpoint is changing the claim types of some of claims to types like "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname". This creates an additional breaking change our consuming clients need to address. Ideally we want to not change anything about the data they are used to mapping, especially as its not clear what triggers some claims to be renamed and what they are renamed too (for example strangling we have a "subjectId" claim that gets changed to "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" which doesn't seem the most obvious match.

Current workaround

The current workaround i have implemented (as i am not aware of a better solution at the moment) is a custom claims transformer to replace the claims with the original type names but this seems sub optimal and requires knowing in advance what claims need transforming.

Possible solution

Ideally a BFF option to disable the claim types being changed would be best so it can transparently just pass through the claims as they were received. If not an easier with to map claims without implementing a custom transformer would be helpful.

Question: Blazor BFF with Additional API

I'm using Blazor BFF from the samples repository witch already sets up the authentication for the "local" api on the server project.

// HTTP client configuration
builder.Services.AddTransient<AntiforgeryHandler>();
builder.Services.AddHttpClient("backend", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)).AddHttpMessageHandler<AntiforgeryHandler>();
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("backend"));

Is there a way to register another API passing the token? I.e:

builder.Services.AddScoped<UserService>();
builder.Services.AddHttpClient<UserService>("API", client => client.BaseAddress = new Uri(builder.Configuration["API"]!));

I'm aware of the AddHttpMessageHandler and could create my own Handler to add the AuthenticationHeaderValue but i'm wondering if there is already something inbuilt?

PS. The API is protected by the same IdentityServer.

IOException: IDX20807: Unable to retrieve document from: 'System.String'. HttpResponseMessage: 'System.Net.Http.HttpResponseMessage', HttpResponseMessage.Content: 'System.String'.

Which version of Duende IdentityServer are you using?
Duende.IdentityServer 6.0.0-preview.6
Duende.BFF 1.1.3

Which version of .NET are you using?
6.0.200

Describe the bug
Getting error when running Quick Start Sample "JavaScript applications with a backend". When clicking login I am getting the error.

I am running on Mac using Visual Studio Code

I first tried to create the apps per the docs. I got this error. Then I cloned the QuickStart samples and got the same error when just running the sample.
https://github.com/DuendeSoftware/Samples/tree/main/IdentityServer/v6/Quickstarts/6_JS_with_backend/src

To Reproduce

  1. Run the IdentityServer in the quick start sample
  2. Run the JavaScriptClient in the quick start sample
  3. Click Login

Then I get the error IDX20807 as shown below in stacktrace.

Note: If I don't run the IdentityServer I get a different error so I think it is communicating with IdentityServer properly.

Expected behavior
The user should be logged in per the sample docs: https://docs.duendesoftware.com/identityserver/v6/quickstarts/js_clients/js_with_backend/

Log output/exception with stacktrace

System.IO.IOException: IDX20807: Unable to retrieve document from: 'System.String'. HttpResponseMessage: 'System.Net.Http.HttpResponseMessage', HttpResponseMessage.Content: 'System.String'.
   at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
   at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)

System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
 ---> System.IO.IOException: IDX20807: Unable to retrieve document from: 'System.String'. HttpResponseMessage: 'System.Net.Http.HttpResponseMessage', HttpResponseMessage.Content: 'System.String'.
   at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
   at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
   --- End of inner exception stack trace ---
   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsyncInternal(AuthenticationProperties properties)
   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsync(AuthenticationProperties properties)
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.ChallengeAsync(AuthenticationProperties properties)
   at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
   at Duende.Bff.DefaultLoginService.ProcessRequestAsync(HttpContext context) in /_/src/Duende.Bff/Endpoints/DefaultLoginService.cs:line 48
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Duende.Bff.Endpoints.BffMiddleware.Invoke(HttpContext context) in /_/src/Duende.Bff/BffMiddleware.cs:line 108
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Additional context

Add any other context about the problem here.

Thank you for your help!
Tom

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.