How do you configure a Blazor Server application using Azure AD in a load balanced environment? - azure-active-directory

I have an intranet Blazor Server application created using the Visual Studio template with the Work or School Accounts authentication option. Everything was working beautifully when running on my local machine and when the app was published to our development environment. However, once I moved the app to our staging environment, the application would sometimes crash after authenticating the user in Azure.
After troubleshooting the issue, I believe the problem to be that our on-premises staging environment is load balanced (mimicking production). Our dev environment is not load balanced. I think what was occurring was that once authenticated in Azure and redirected back to the application, the user doesn't always land on the same server due to the load balancer. This breaks the Signal-R circuit and caused the application to crash. This also explains why the error was random; happening maybe 2 out of every 10 logon attempts. To test this, I removed Azure AD authentication from the application and allowed anonymous access to every page. The crashes stopped.
My question is if anyone knows of any workaround to get Blazor Server with Azure AD authentication working with an on-premises load balancer. I searched all over the web and the only workaround I found was to use sticky sessions with Azure Signal R service. We are not hosting apps on the cloud yet. Is switching to Blazor Webassembly the only option if I want to use Blazor with authentication in my environment? Someone at work suggested switching the application to use our on premises ADFS server. However, wouldn't that encounter the same issue?
For reference, here is the code in startup.cs ConfigureServices method that sets up the Azure authentication in the application:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
});

I found the solution to this and am posting it here in case anyone else is facing a similar issue.
It turns out the problem wasn't SignalR or anything specific to Blazor Server. After enabling the developer exception page on the load balanced environment, I saw that the error was "Unable to unprotect the message.State". The application state is encrypted by middleware before the user is authenticated by Azure AD. When Azure AD posts back, it includes that encrypted state which is then in turn decrypted on the client side by the middleware.
The key needed to decrypt is by stored on the web server. When in a load balanced environment, if you land on a different server than where you started, the middleware will then be attempting to decrypt state with the wrong key. This of course results in an error.
To fix this you have to store the keys on a central location like a file share instead of on the server itself. Implementing the fix is actually simple. Include the following line in ConfigureServices in startup.cs:
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"\\server\share\directory\"));
There are also options to store keys on Azure if that is preferred.
This post by Kevin Dockx is what finally gave me the answer:
Solving Correlation Failed: State Property Not Found Errors (OpenID Connect Middleware / ASP.NET Core)

Related

Does anyone know how to set up OpenIdConnect Auth using Azure Active Directory and React SPA without storing access token in the broswer

I am trying to build an app where users can sign in using their work Microsoft account through open id connect. All of the documentation on Microsoft seems to suggest that for React/SPA apps you should use the MSAL library to authenticate users but this seems to cache the access tokens directly in the brower through session storage. To my knowledge this is bad practise and a backend for frontend approach should be used for this scenario instead where the access token is stored in a HTTP secure cookie.
Does anyone know how to do a backend for frontend type approach using Azure Active Directory? Is there support for this using Microsoft Api's or do I have to just write the code from scratch?
Thanks for any help
You need to use a server side solution to issue application level secure cookies. It is not specific to Azure AD.
The Duende BFF solution is .NET based, and uses the web host, eg https://www.example.com, to issue cookies. See this code example and the docs.
It is also possible to issue cookies via a utility API that runs in a sibling domain of the SPA, eg https://api.example.com. This is a little more complex, but provides options such as deploying the SPA to a content delivery network - see this code example.

Blazor Standalone PWA offline Authentication/Authorization with AAD

I had a look a lot of days to find a solution for my problem regarding offline authentication of a user in my Blazor Standalone PWA.
With .Net 5.0 I changed the Authentication scenario on Azure AD from Web to SPA.
After that change, my PWA was not able to login the user in offline mode.
I work on Program.cs with AddMsalAuthentication and save the tokens and ID's in local storage with help of MSAL.
If I'm online everything works like expected and I can login with the users and the tokens will be stored in local storage.
After changing the online state, the PWA try to get the openid-configuration data from azure.
I tried to also serve this request with the service worker, which worked quite fine but the token request after that fails also.
I searched and found the CarChecker app and the docs as well but this didn't solve my problem.
Did I missed something or is there really no way, to make offline auth workable on Blazor Standalone PWA's?

Azure AD B2C Application Change in Manifest shows Internal Server Error

I have recently Registered a Keycloak Application on my Azure AD B2C tenant, one of my colleagues accidentally deleted the registration, so i have restored the application on the Azure portal, Later i tried changing the Redirection URI, but the Azure portal doesn't allow me to do so and shows the below error
"Failed to update KeyCloak application. Error detail: Encountered an internal server error."
I have tried to change the same in the Manifest and tried to upload file, even it shows the same error.
Did my application restore made any difference here, if it was so please suggest me some check points to solve this.
Note : The other applications in this tenant allow me to do same changes, I have issue only with this application registration.
A bug has been filed and the product team is working on it. In the mean time for the work around Please re-create another app if possible.
You could also try to change "SignInAudience" to "AzureADMultipleOrgs" (if it works) - than you'll be able to modify reply urls and switch "SignInAudience" back.

Azure AD Authentication of Angular app with MVC Core on Azure AppService

I'm investigating options for adding AzureAD authentication to Angular SPA application with .NET core backend. I'm using VS 2019 MVC project with Angular (same as dotnet new Angular is producing). It's using .NET Core 3.1 and Angular 8.
From what I learned so far I have 3 options:
Built in Azure App Service Authentication
Adal.js - looks like the older brother of,
MSAL.js - which after making it work locally with Azure AD I learned on this page that "At this time, AAD V2 (including MSAL) is not supported for Azure App Services and Azure Functions. Please check back for updates." I couldn't make it work on Azure today so maybe this Note is for a good reason.
EDIT: Interestingly now point 3 works for me on Azure App Service so I'm not sure what this note means.
My requirements so far are that no screen is accessible to users unless they log in and that I will be able to read information about them from Azure AD - Roles, groups.
I never worked with Angular and I don't have any experience with Azure AD and I need someone that implemented it already to at least tell me which option I should choose and I can go from there.
My requirements so far are that no screen is accessible to users unless they log in and that I will be able to read information about them from Azure AD - Roles, groups.
I think the option 1 could meet your requirement, the configuration of Azure AD in Authentication / Authorization is higher than your code, the user could not access the app unless they log in.
To read the information about the roles, groups, you could check this good blog.
Here you have an angular E2E auth scenario using App Service built in authentication:
https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-auth-aad
I believe the part you are interested in is this one:
Enable authentication and authorization for front-end app
This way app service is the one redirecting you to AAD and getting a valid token that you can just pass in to your APIs afterwards. If the APIs are hosted in App Service as well, then APP service will be the one validating the token for you, so your backend code does not need to worry about authentication (you still need to handle authorization)

IdentityServer4 Restart causes 401 unauthorized until API app pool is reset due to metadata

We have an IdentityServer4 Host as our IDP. We have a 4.6 WEB (SPA) calling an API using Hybrid flow (Calling the API by passing the accessToken). Everything is working as expected. Please note that on the API we are using IdentityServer3.AccessTokenValidation package to authenticate with IdentityServer4.
Scenario
Restarting Identity Server 4 Host causes newly logged do users a 401 unauthorized call to the API. We know of 2 solutions how to solve this issue:
1.) Restart the API App Pool (undesired)
2.) In the API, setup of app.UseIdentityServerBearerTokenAuthentication to set AutomaticRefreshInterval to 5 minutes of caching. After 5 minutes, newly logged on users can now retrieve data from the API.
The question is:
1.) Is there another option we can do beside what is mentioned above?
2.) If we do set the AutomaticRefreshInterval to the lowest possible cache value of 5 minutes, can you foresee any potential issues that we should account for? e.g. performance issues, security concerns, etc?
If using a temporary in-memory signing key then you'll get this behaviour. You need to create a persisted signing credential like an X509 certificate and load it when your IDS4 service starts.
Some guidance here: http://docs.identityserver.io/en/release/topics/startup.html#refstartupkeymaterial
See my answer here for a code sample on how to load a cert or certs from the machine certificate store:
How we can replace AddDeveloperSigningCredential on AWS Serverless Lambda environment?

Resources