
AWS Cognito + Microsoft Blazor WASM, with a little help from Claude
I’m not a UI expert, but I like to think there is nothing too hard about (basic… very basic) UI work, so Anthropic’s Claude and I spent some time together recently implementing an integration between Microsoft Blazor Web Assembly and AWS Cognito so that I could use it as a cornerstone of some of my future work. For those new to the world of user/customer authentication, Cognito is Amazon’s service to which you can outsource user registration and login/logout, including a hosted web user interface, and Microsoft Blazor is Microsoft’s way to bring C# into web page/component development in a way that integrates with JavaScript through an Interop middleware that allows C# to co-exist and collaborate with JavaScript. Think Apple’s use of Swift and Objective C when building modern UIs on the Apple tech stack: both languages interact (pretty) smoothly.
I didn’t start out working with Claude, but the dearth in documentation about how to implement this integration, especially as it relates to Amazon’s possibly not-as-compliant OIDC Cognito implementation, left me searching through Stackoverflow and the other usual places to search for guidance from people who have gone before. While there are bits and pieces in what I found, I didn’t find them as consumable as I needed, so I leaned on Claude to help in my search, and to generate a few lines of code where this made sense. Since learning is a tide that can lift all boats, I thought it reasonable to share what I’ve learned to help those like me who are just becoming familiar with some of these tech stack combinations but don’t quite find satisfaction in the breadcrumb trails they’ve found to date.
You may be curious about why I choose to use AWS Cognito for my forthcoming work — of course, you may not, too, but I found quite a few people wondering about Cognito vs. Okta, Auth0, and Azure AD as I searched for answers. There are two reasons that I view to be near-term optimums currently:
1. Cost. The fact of the matter is that Amazon, Microsoft, WorkOS, Auth0, and others provide generous free tiers, so the comment of cost has a strategic dimension of use with scale. This is not to say that deals cannot be had, but I’ve researched some of these in the past and found their cost with large customer pools can become prohibitively expensive.
2. Integration between AWS services. The integrations between AWS services often save many steps and, since my cloud target for the work I currently am doing is AWS, integrations translate to efficiencies.
You may be part of a company that has negotiated stellar rates with a different auth provider. First, good on you if you’ve negotiated good rates at scale 😁… this small guide might be of help to you in any event. Second, cloud service providers change their rates often enough that our Cloud FinOps partners may guide us in the future to seek out better rates — what might be cost effective today may not be tomorrow. Third, cloud providers implement new services and integrations between them all the time. SO… my choice of AWS and Cognito should not be misconstrued as a recommendation of one auth or cloud provider over another. In fact, I’ve seen where some people use Azure AD in combination with AWS.
To save readers’ time:
· The tech stack being used is .NET 8/C#, Blazor Web Assembly standalone application, and AWS Cognito.
· The result of this work is a standard Blazor WASM application with Authentication provisioned by AWS Cognito.
· There likely are many more and probably better ways to accomplish this goal, but I could not find them. Your mileage may vary with this work, but I hope some might find it useful. Project source code can be found here.
· This work was done in Nov 2024. Who knows how long this summary will be of value… 😉
The gist of how I integrated Cognito with Blazor WASM (at least for now) is summed in the following task list and subsequent summary.
1. Create an AWS Cognito user pool, which obviously requires you to have an Amazon AWS account.
I use email as the Name claim and require MFA to be set up for users who become part of my pool. I do not collect phone number data. I do not implement SMS text messaging to users or social network authentication. And I outsource the UI for registering new users and logging them into my application to Cognito (I use Cognito’s Hosted UI).
2. Create a Blazor WASM project with authentication to save a few dotnet package-related steps.
3. Modify a few of the generated project files to set up authentication and add a small bit of JavaScript to override timeout values that default in Microsoft’s silent sign-in JavaScript to result in an unpleasantly long 10-second timeout when the application initially launches.
I don’t intend to walk through a Cognito tutorial or the code of this project in any real detail in the subsequent part of this article, but I would like to highlight a few things on which I initially stubbed my toes.
When creating a Cognito User Pool…
Creating a user pool (not an Identity pool) is straightforward. Navigate to Cognito in your AWS account and pretty much follow a commonsense path to create your pool.

You’ll provide a pool name, and Amazon will assign a pool ID to it that you’ll need when configuring your Blazor application:

You’ll need to take note of the domain name Amazon provides you:

And you’ll need to create an application client through which your users will access your user pool:

Client secrets aren’t needed in my work as the users will access my applications externally and I won’t be sharing any secrets with them. The Client ID will be needed to configure Blazor.
Results of searching about callbacks showed a mix of configurations. The boilerplate Blazor application is used, with the Weather menu item secured via login, and logout routes to the main site index.html. You may wish to configure your app differently, but the configuration for this application to use the Hosted UI (for signing in and for registering) is as follows:

You’ll need both URLs above to configure Blazor services.
Anyone curious about the https port need only look in the launchSettings.json file created in your project’s Properties folder. Of course, you may adjust the port configurations, just note that your Cognito and Blazor app settings ultimately must match:

You may wish to view and even test the Hosted UI, which you can do via Cognito’s configuration interface:

I used it to create my initial user. At first, I simply set the initial callbacks to https://localhost to make my life simpler. Then I subsequently replaced the login and sign-out callbacks to application-specific values.

The Hosted UI is spartan (which leads to criticisms interlaced with my search results… you critics know who you are, and I have no doubt you can do much better from scratch… 😎), and those with more UI skills than I can dress this up a bit (but not too much) with the Cognito Hosted UI customization options to provide CSS and a logo image.
Now the Blazor Part
Just to get started on the right foot by having dotnet create the full template that is needed for this project, I used the CLI command “dotnet new blazorwasm — use-program-main -au Individual -o BlazorCognito”. FYI, I am one who doesn’t like the top-level statement thing that Microsoft has done — if you do, then remove the “ — use-program-main” part of this command (and note that the long dash is actually two dashes followed by no space on the command line). The -au switch causes dotnet to wire in the authentication scaffolding that we need, including various packages that we otherwise would need to add manually.
Now I would like to call attention to two bits of code that are important, and I assume you’ll download the code and read the rest if you have interest.
First, the code that sets services up in Program.cs:

Read the highlighted areas as follows:
1. Replace the capitalized text with the values relating to your Cognito user pool and application client.
2. Be careful to use the cognito-idp endpoints when depending on the Hosted UI.
3. I do not know the underpinnings relating to profile, but adding it as suggested in some of the on-line search results I found met with failure given my configuration that only requires email (Name claim) and MFA.
Use of appSettings.json to store some of these data bits is considered better form than putting these into code but, as plenty of school textbook authors have done, I leave this as an exercise to interested readers.
The above covers login, but not logout, which I have separated into Authentication.razor:

For whatever reasons, logout implementation was a bit troublesome and led to this separation. In the process of debugging and sorting through the ways that various people implemented their solutions, I learned the following:
1. Key findings from multiple tries and fails re logout problems:
a. Use the correct hosted UI path ‘/logout’ (not ‘/oauth2/logout’). This might be obvious to some, but I tripped over this.
b. Use ‘logout_uri’ (not ‘redirect_uri’)
c. Use the ‘<LogOut>’ template in Authentication.razor (instead of ‘<LogOutSucceeded>’)
d. Use the Cognito domain URL format ‘https://{cognitoDomain}/logout’
e. Remove the possibility of OIDC middleware’s interference with logout by not setting certain options
2. The working final solution used:
a. The Cognito-hosted UI domain for logout
b. Simple parameter structure with just ‘client_id’ and ‘logout_uri’ because of details with which I was not familiar that seemed to get in the way of success
c. Direct navigation rather than relying on the OIDC middleware’s logout flow
And Some JavaScript Tweaks
Finally, I made a few JavaScript tweaks to minimize the impact of default timeout values that Microsoft implemented as part of its AuthenticationService.js implementation. The integration of auth-settings-override.js can be seen in the index.html file as shown below:

I chose to supplement what Microsoft provided rather than textually edit it so that I didn’t have to subsequently maintain it. “Brett” (stackoverflow), who diagnosed this silent sign-in problem (thank you!) discussed the potential — one day — that Microsoft might allow the API-driven disablement of silent sign-in. Maybe. And maybe the fix below is a near-term compensation for Microsoft not doing so in the last few years since Brett pointed it out.
The motivation to provide the override is that the Blazor template wires signing in automatically and silently into the application, but it does so at the cost of about 10 seconds of idle time that results in a poor user experience. So, the following code is installed to set timeouts to a very short period (5 milliseconds, not 0 — which AuthenticationService appears to replace with default 10s values) upon creation of the userManagerCore object.

In Sum
While the above is not perfect by any stretch, it works, and this document gathers all (of what I think are the) needed pieces to explain it in one place. Hopefully this will be a help and a time savings to those that know as much or less than I, and fodder for those who know more to point to better alternatives. If we all get to learn from critique, it is most welcomed.