(sp => { var client = new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }; client.DefaultRequestHeaders.Add("X-CSRF", "1"); return client; }); ``` Alternatively, a [handler](https://duendesoftware.com/blog/20250902-dotnet-httpclient-and-delegating-handlers) can be created and used with the `HttpClient` instance. And with this in place, the application should be able to fetch data from the API endpoint when the Weather page is shown. ## Setting Up A Blazor BFF client In IdentityServer [Section titled “Setting Up A Blazor BFF client In IdentityServer”](#setting-up-a-blazor-bff-client-in-identityserver) In essence, a BFF client is “just” a normal authorization code flow client: * use the code grant type * set a client secret * enable `AllowOfflineAccess` if you want to use refresh tokens * enable the required identity and resource scopes * set the redirect URIs for the OIDC handler Below is a typical code snippet for the client definition: ```csharp var bffClient = new Client { ClientId = "bff", ClientSecrets = { new Secret("secret".Sha256()) }, AllowedGrantTypes = GrantTypes.Code, RedirectUris = { "https://bff_host/signin-oidc" }, FrontChannelLogoutUri = "https://bff_host/signout-oidc", PostLogoutRedirectUris = { "https://bff_host/signout-callback-oidc" }, AllowOfflineAccess = true, AllowedScopes = { "openid", "profile", "remote_api" } }; ```
-----
# Building Browser-Based Client Applications
> Overview of browser-based client application patterns and security considerations when implementing JavaScript clients with IdentityServer
When building browser-based or SPA applications using javascript, there are two main styles: those with a backend and those without. Browser-based applications **with a backend** are more secure, making it the recommended style. This style uses the [“Backend For Frontend” pattern](https://duendesoftware.com/blog/20210326-bff), or “BFF” for short, which relies on the backend host to implement all the security protocol interactions with the token server. The `Duende.BFF` library is used in [this quickstart](/identityserver/quickstarts/javascript-clients/js-with-backend/) to easily support the BFF pattern. Browser-based applications **without a backend** need to do all the security protocol interactions on the client-side, including driving user authentication and token requests, session and token management, and token storage. This leads to more complex JavaScript, cross-browser incompatibilities, and a considerably higher attack surface. Since this style inherently needs to store security sensitive artifacts (like tokens) in JavaScript reachable locations, **this style is not recommended**. As the [“OAuth 2.0 for Browser-Based Apps” IETF/OAuth working group BCP document](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps) says: > there is no browser API that allows to store tokens in a completely secure way. Additionally, modern browsers have recently added or are planning to add privacy features that can break some front-channel protocol interactions. See [here](/bff/#3rd-party-cookies) for more details.
-----
# Browser-Based Applications With A BFF
> Guide to building secure browser-based JavaScript applications using the Backend For Frontend (BFF) pattern with Duende.BFF library
In this quickstart, you will build a browser-based JavaScript client application with a backend. This means your application will have server-side code that supports the frontend application code. This is known as the Backend For Frontend (BFF) pattern. You will implement the BFF pattern with the help of the `Duende.BFF` library. The backend will implement all the security protocol interactions with the token server and will be responsible for management of the tokens. The client-side JavaScript authenticates with the BFF using traditional cookie authentication. This simplifies the JavaScript in the client-side, and reduces the attack surface of the application. The features that will be shown in this quickstart will allow the user to log in with IdentityServer, invoke a local API hosted in the backend (secured with cookie authentication), invoke a remote API running in a different host (secured with an access token), and logout of IdentityServer. ## New Project For The JavaScript Client And BFF [Section titled “New Project For The JavaScript Client And BFF”](#new-project-for-the-javascript-client-and-bff) Begin by creating a new project to host the JavaScript application and its BFF. A single project containing the front-end and its BFF facilitates cookie authentication - the front end and BFF need to be on the same host so that cookies will be sent from the front end to the BFF. Create a new ASP.NET Core web application and add it to the solution by running the following commands from the `src` directory: Terminal ```bash dotnet new web -n JavaScriptClient cd .. dotnet sln add ./src/JavaScriptClient ``` ### Add Additional NuGet Packages [Section titled “Add Additional NuGet Packages”](#add-additional-nuget-packages) Install NuGet packages to add BFF and OIDC support to the new project by running the following commands from the `src/JavaScriptClient` directory: Terminal ```bash dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect dotnet add package Duende.BFF dotnet add package Duende.BFF.Yarp ``` ### Modify Hosting [Section titled “Modify Hosting”](#modify-hosting) Modify the `JavaScriptClient` project to run on `https://localhost:5003`. Its `Properties/launchSettings.json` should look like this: ```json { "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { "JavaScriptClient": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "https://localhost:5003", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } ``` ### Add Services [Section titled “Add Services”](#add-services) In the BFF pattern, the server-side code triggers and receives OpenID Connect requests and responses. To do that, it needs the same services configured as the WebClient did in the prior [web application quickstart](/identityserver/quickstarts/3-api-access/). Additionally, the BFF services need to be added with `AddBff()`. In addition, the offline\_access scope is requested that will result in a refresh token that will be used by the BFF library to automatically refresh the access token for the remote API if needed. Add the following to `src/JavaScriptClient/Program.cs`: * Duende BFF v4 Program.cs ```csharp using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Duende.Bff.Yarp; using Microsoft.AspNetCore.Authorization; var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthorization(); builder.Services .AddBff() .ConfigureOpenIdConnect(options => { options.Authority = "https://localhost:5001"; options.ClientId = "bff"; options.ClientSecret = "secret"; options.ResponseType = "code"; options.Scope.Add("api1"); options.Scope.Add("offline_access"); options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.MapInboundClaims = false; }) .ConfigureCookies(options => options.Cookie.SameSite = SameSiteMode.Strict) .AddRemoteApis(); var app = builder.Build(); ``` * Duende BFF v3 Program.cs ```csharp using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Duende.Bff.Yarp; using Microsoft.AspNetCore.Authorization; var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthorization(); builder.Services .AddBff() .AddRemoteApis(); builder.Services .AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; options.DefaultSignOutScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.Authority = "https://localhost:5001"; options.ClientId = "bff"; options.ClientSecret = "secret"; options.ResponseType = "code"; options.Scope.Add("api1"); options.Scope.Add("offline_access"); options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.MapInboundClaims = false; }); var app = builder.Build(); ``` ### Add Middleware [Section titled “Add Middleware”](#add-middleware) Similarly, the middleware pipeline for this application will resemble the WebClient, with the addition of the BFF middleware and the BFF endpoints. Continue by adding the following to `src/JavaScriptClient/Program.cs`: Program.cs ```csharp var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseDefaultFiles(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseBff(); app.UseAuthorization(); app.MapBffManagementEndpoints(); app.Run(); ``` ### Add HTML And JavaScript Files [Section titled “Add HTML And JavaScript Files”](#add-html-and-javascript-files) Next, add HTML and JavaScript files for your client-side application to the `wwwroot` directory in the `JavaScriptClient` project. Create that directory (`src/JavaScriptClient/wwwroot`) and add an `index.html` and an `app.js` file to it. *`index.html`* The index.html file will be the main page in your application. It contains * buttons for the user to login, logout, and call the APIs * a `` container used to show messages to the user * a `