Authentication with Azure Static Web Apps and Blazor (WebAssembly)


Posted on 03/05/2021


As of now Azure Static Web Apps are in Preview

Azure Static Web Apps is a great place to host your static web apps. Besides many amazing feature, it has built-in support for authentication.

Azure Static Web Apps takes care of dealing with identity providers like GitHub, Twitter, or even Azure AD. You do not need to write a single line of code for handling any identity provider. You even can access the user properties using a built-in API.

Blazor WebAssembly can integrate custom authentication providers.

Basic Setup

(I assume you are familiar with setting up a simple Blazor Web Assembly project, otherwise checkout this) To utilize Authentication of Static Web Apps in Blazor, we need to inject the authentication provider.

Install NuGet

Anthony Chu has written an amazing Nuget package to simplify the process.

dotnet add package AnthonyChu.AzureStaticWebApps.Blazor.Authentication --version 0.0.2-preview

We will also need to add the Microsoft.AspNetCore.Components.WebAssembly.Authentication package.

 dotnet add package Microsoft.AspNetCore.Components.WebAssembly.Authentication

Registering the Service

After the package is installed, we can use AddStaticWebAppsAuthentication() in the Program.cs. This will register the Static Apps AuthenticationStateProvider.

Add the following using directive:

using AzureStaticWebApps.Blazor.Authentication;

Update the Main method to load the authentication provider by adding .AddStaticWebAppsAuthentication();

public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("#app");

            builder.Services.AddScoped(sp => new HttpClient 
            { 
                BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) 
            })
            .AddStaticWebAppsAuthentication();

            await builder.Build().RunAsync();
        }

Modify the Blazor Template

Blazor doesn't use Authentication out of the box. To enable authentication we need to Update the App.razor file. By adding &lt;CascadingAuthenticationState&gt; and by replacing the &lt;RouteView&gt; component to &lt;AuthorizeRouteView&gt;.

This will expose the authentication state through the app as cascading parameter.

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                        <RedirectToLogin />
                </NotAuthorized>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

In the _Imports.razor file we need to add the following:

@using Microsoft.AspNetCore.Components.Authorization

Authentication

As we have done the basics now we can use authentication in Blazor. In order to to do this we need to add one little thing. We need to provide an option to authenticate. Azure Static Web App provides some endpoints to use.

For example, we can use /.auth/login/github to authenticate against GitHub. And to logout the user we can leverage /.auth/logout

In the Shared folder, we will create a new File RedirectToLogin.razor.

@inject NavigationManager Navigation
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@code {
    protected override void OnInitialized()
    {
        Navigation.NavigateTo($"/.auth/login/github", true);
    }
}

This component is referenced in the app.razor file. Whenever an unauthorized request is processed it will be redirected to the authentication endpoint.

If we run this app now we should be redirected to the authentication endpoint.

Access Control

As Blazor is a public client application any page is available on the client-side. If we want to protect secure data we need to host it in properly secured backend APIs.

Preventing unauthenticated users to see pages

To protect pages from being accessible to unauthenticated users we can place the following attribute at the top of the page.

@using Microsoft.AspNetCore.Authorization
@attribute [Authorize()]

Blocking access to API

Simply locking down pages or links in the client isn't enough. An unauthorized user can still retrieve data from the backend APIs.

We can create a routes.json file in the *wwwroot * folder. This will tell Azure Static Web Apps how to handle server-side routing rules.

{
    "routes": [{
            "route": "/api/*",
            "allowedRoles": ["authenticated"]
        },
        {
            "route": "/*",
            "serve": "/index.html",
            "statusCode": 200
        }
    ]
}

This file defines two routing rules. The first one restricts access to the API to authenticated users. The second one is a standard rule for single-page applications. This is required for fallback routes and which allows deep linking to work.

If you want to allow only invited users to access the API change the role to a custom role you assigned a user.
Azure Static Web App Role Management view

That's it, your Static Web App should now be capable of using authentication and authorization.

If you want to check out the complete code feel free to take a look at GitHub