Blazor.BFF.AzureB2C.Template
This template can be used to create a Blazor WASM application hosted in an ASP.NET Core Web app using Azure B2C and Microsoft.Identity.Web to authenticate using the BFF security architecture. (server authentication) This removes the tokens form the browser and uses cookies with each HTTP request, response. The template also adds the required security headers as best it can for a Blazor application.
Features
- WASM hosted in ASP.NET Core 6
- BFF with Azure B2C using Microsoft.Identity.Web
- OAuth2 and OpenID Connect OIDC
- No tokens in the browser
Other templates
Blazor BFF Azure OpenID Connect
Using the template
install
dotnet new -i Blazor.BFF.AzureB2C.Template
run
dotnet new blazorbffb2c -n YourCompany.Bff
Use the -n
or --name
parameter to change the name of the output created. This string is also used to substitute the namespace name in the .cs file for the project.
Setup after installation
Add the Azure B2C App registration settings
"AzureB2C": {
"Instance": "https://--your-domain--.b2clogin.com",
"Domain": "[Enter the domain of your B2C tenant, e.g. contoso.onmicrosoft.com]",
"TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]",
"ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]",
"ClientSecret": "[Copy the client secret added to the app from the Azure portal]",
"ClientCertificates": [
],
// the following is required to handle Continuous Access Evaluation challenges
"ClientCapabilities": [ "cp1" ],
"CallbackPath": "/signin-oidc"
// Add your policy here
"SignUpSignInPolicyId": "B2C_1_signup_signin",
"SignedOutCallbackPath": "/signout-callback-oidc"
},
Add the permissions for Microsoft Graph if required, application scopes are used due to Azure B2C
"GraphApi": {
// Add the required Graph permissions to the Azure App registration
"TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]",
"ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]",
"Scopes": ".default"
//"ClientSecret": "--in-user-secrets--"
},
uninstall
dotnet new -u Blazor.BFF.AzureB2C.Template
Development
build
https://docs.microsoft.com/en-us/dotnet/core/tutorials/create-custom-template
nuget pack content/Blazor.BFF.AzureB2C.Template.nuspec
install developement
Locally built nupkg:
dotnet new -i Blazor.BFF.AzureB2C.Template.1.0.7.nupkg
Local folder:
dotnet new -i
Where
is the path to the folder containing .template.config.
Azure App registrations documentation
https://docs.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications
Credits, Used NuGet packages + ASP.NET Core 6.0 standard packages
- NetEscapades.AspNetCore.SecurityHeaders
- IdentityModel.AspNetCore
Links
https://github.com/AzureAD/microsoft-identity-web
Correlation failed error when deployed to container apps and app service containers - missing cookies, maybe samesite issue?
Hello @damienbod ,
I watched your recent stand-up with Jon Galloway which was super interesting and I thought I'd give this BFF template a go. Locally it works great, and deployed to a standard app service plan it works fine too. However, I'm pulling my hair out trying to get it to work with Azure container apps and was hoping you could point me in the right direction to fix this. Please note, before the index page would work I had to I fix another issue with the anti-forgery cookie which was resolved with the following change:
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
to
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
Once the above was resolved the index page shows fine but I unfortunately get the correlation failed error reported below when selecting the login link. Any help with this is greatly appreciated:
Issue
Correlation failed error reported when selecting the log-in link on the main page. The container app logs show the following (newest first):
[40m[1m[33mwarn[39m[22m[49m: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[15]
'.AspNetCore.Correlation.JV4ZtwsqyoQzUm0XjKPsZl5UeG7IAsHK18V9J3fEtwU' cookie not found.
[40m[1m[33mwarn[39m[22m[49m: Microsoft.AspNetCore.Http.ResponseCookies[1]
The cookie '.AspNetCore.Correlation.JV4ZtwsqyoQzUm0XjKPsZl5UeG7IAsHK18V9J3fEtwU' has set 'SameSite=None' and must also set 'Secure'.
[40m[1m[33mwarn[39m[22m[49m: Microsoft.AspNetCore.Http.ResponseCookies[1]
The cookie '.AspNetCore.OpenIdConnect.Nonce.CfDJ8P3OW6sbpfpEkZYp1w0JsW8f2E0rMU4me_SA7Co14Nm2S8UlmZSemDj0yeKD7P5em5sNOV_0CUKPl2JSHAmZWAqJ1GU_Ni9PMQJSPoMEaGjWmJvwp-0SRuAfja8V4tnB1FFiUapJtdRH_KCWCjo_IXrGJlpg6_7b-zkZ8xl0_GxwOSIk-gOT8150GvMagOBwG8_3W5V3M-GwnpfdQt96kA8WzYNqBVgUUdbe8N821B9ac4_NqG37gna1ubwXtF1MmlQ63XVYkMREGaGWAKY87F0' has set 'SameSite=None' and must also set 'Secure'.
To Reproduce
Enable container orchestration and deploy the BFF server to a container registry.
Create a container app (and supporting resources such as environment, app insights etc.). and deploy the image above.
On the main index page select the 'Log in' link and you will be redirected to the /MicrosoftIdentity/Account/Error page which states 'Correlation failed.'
Additional notes
Deploying to a standard app service plan works fine.
Deploying to a container based app service plan does not work either, also producing a 'correlation failed' error. This is probably the quickest path to reproducing the issue as it only takes a few minutes to create the app service.
Many Thanks,
Roger
Upon app JS Logout(Signout command) does not display Azure AD B2C login page
Hi Damien,
VSDotNetGuy again. We see in your template, you're using a form post based logout to the server side api. However, we're using a menu drawer based Logout link that when clicked raises an event. From the event code we post to the server at \api\account\logout using HttpClient.
The server side Logout method is being called and the Signout command seems to run okay. However, we expected the app would no longer be authenticated so would display the Azure AD B2C login page upon redirect or refresh.
Does your template prompt for AD login after Signout? If not, any ideas on how to be prompted by Azure AD B2C to login after the server side Signout is completed?
Thx in advance and take care, Bob Baldwin (aka VSDotNetGuy)
Update readme regarding Azure Container support
Hello Damien, please find attached the documentation change to describe what to do if experiencing issues after deploying the app to Azure container based services. Apologies if the format is unorthodox or anything, this is my first PR request on someone else's repo! Many Thanks, Roger
Switch to MicrosoftIdentityOptions to support downstream apis
instead of
DirectController
Hi Damien,
I've been looking at the AD B2C BFF Blazor template, it looks good, thx for great work.
I did wonder since include global anti forgery setting in Startup, why did you put [ValidateAntiForgeryToken] on DirectApiController or is this just a left over?
Thx...Bob Baldwin aka VSDotNetGuy!
Update the GraphApiClaimsTransformation class to use the objectidentifier
var objectidentifierClaimType = "http://schemas.microsoft.com/identity/claims/objectidentifier"; var objectIdentifier = principal.Claims.FirstOrDefault(t => t.Type == objectidentifierClaimType);
Template for Blazor WASM not Hosted
Hi @damienbod Have you ever done this, or got it on the list of things to try for the future? My app architecture is ASPNET BFF Server, and a standalone Blazor WASM app. I have been trying to hack this template so it isn't intertwined with the WASM Hosted approach but I am struggling with it.
Unhandled exception when logging out after logging-in on multiple browser tabs
Hi,
First of all thanks for this fantastic resource!
I build a Blazor App using the template and can login/logout with my AD B2C tenant. When I open the App in a second tab, I am already signed in (as expected). If I now sign-out in either tab, and then click on the Direct-API link in the navbar on the other tab, I get an exception (in the Blazor Client) that looks like a malformed JSON object is being parsed.
This happens in Chrome and Safari on MacOS, but (curiously) not on Firefox, there I get redirected to sign in again (as expected).
I probably did something wrong, but I tried to stay as close to the template as possible. Anyway, I am totally baffled and stuck. Obviously I can give you access to my repository with the Blazor SPA. I can be reached by email on gmail or outlook by using firstname.lastname as name (to get the Client-Secret).
This is the exception I get: