1

I am trying to implement single sign on using the Duende Backend for Frontend (BFF) Security Framework.

This GitHub repository demonstrates the behaviour I am seeing.

It contains 3 sites:

  1. Blazor WASM (hosted) - using BFF as described in the official docs
  2. MVC site
  3. Web (Razor Pages) site

The IdentityServer project is configured to serve all of the above.

When logging in via either MVC or Web the Blazor site does not appear to be signed in. When logging in via Blazor all 3 sites appear to be signed in.

Blazor MVC Web
Logging in to MVC N Y Y
Logging in to Web N Y Y
Logging in to Blazor Y Y Y

When logging out via either MVC or Web the Blazor site is not signed out. When logging out via Blazor the Web site is not signed out.

Blazor MVC Web
Logging out of MVC N Y Y
Logging out of Web N Y Y
Logging out of Blazor Y Y N

I am not sure if this is due to the way I have configured the IdentityServer project but I cannot get to the root of the issue.

Newm
  • 1,313
  • 3
  • 16
  • 29

1 Answers1

0

For Duende IdentityServer BFF the following will be okay for client configuration;

new()
            {
                ClientId = "wasmlocal",
                ClientSecrets = { new Secret("secret".Sha256()) },

                AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,

                RedirectUris = { "https://localhost:5002/signin-oidc" },
                
                //FrontChannelLogoutUri = "https://localhost:5002/signout-oidc",
                BackChannelLogoutUri = "https://localhost:5002/bff/backchannel",

                PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" }
                ,
                AllowOfflineAccess = true,
                AllowedScopes = { "openid", "profile", "api 1", "roles", "EmployeeID" }

            }
You may need to configure other resources such Identity Resource and API resources.
While the BackEnd of the Blazor Wasm hosted application,
should be as follows;

    builder.Services.AddAuthentication(options =>
            {
                options.DefaultScheme = "cookie";
                options.DefaultChallengeScheme = "oidc";
                options.DefaultSignOutScheme = "oidc";
            })
            .AddCookie("cookie", options =>
            {
                options.Cookie.Name = "__Host-blazor";
                options.Cookie.SameSite = SameSiteMode.Strict;
                options.ExpireTimeSpan = TimeSpan.FromMinutes(15);
                // sliding or absolute
                options.SlidingExpiration = false;
           
                options.Events.OnSigningOut = async e =>
                {
                    // automatically revoke refresh token at signout time
                    await e.HttpContext.RevokeUserRefreshTokenAsync();
                };
          
            })
            .AddOpenIdConnect("oidc", options =>
            {
             
                options.Authority = "https://localhost:5001/";
                
                options.ClientId = "clientname";
                options.ClientSecret="secret";
                options.UsePkce = true;
                options.ResponseType = "code";
                options.ResponseMode = "query";
                
                options.MapInboundClaims = false;
    
                options.GetClaimsFromUserInfoEndpoint = true;
                options.SaveTokens = true;
    
                // request scopes + refresh tokens
                options.Scope.Clear();
                options.Scope.Add("openid");
                options.Scope.Add("profile");
                options.Scope.Add("API 1");
    
                options.Scope.Add("roles");
          
    
                options.Scope.Add("offline_access");
    
                
    
                options.GetClaimsFromUserInfoEndpoint = true;
    
           
            });
     

Then on the client make sure you coordinate the login flow; by triggering oidc code challenge by attributing  your secure pages with @attribute [Authorize], such as 

@attribute [Authorize]

<h1>Hello, Blazor BFF!</h1>

<AuthorizeView>
    <Authorized>
        <h3>Current session:</h3>
        
        <dl>
            @foreach (var claim in @context.User.Claims)
            {
                <dt>@claim.Type</dt>
                <dd>@claim.Value</dd>
            }
        </dl>
    </Authorized>
</AuthorizeView>

Let me know how it goes.