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.
(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.
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
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();
}
Blazor doesn't use Authentication out of the box. To enable authentication we need to Update the App.razor file.
By adding <CascadingAuthenticationState>
and by replacing the <RouteView>
component to <AuthorizeRouteView>
.
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
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.
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.
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()]
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.
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