This sample demonstrates how to configure AAD Authorization in a Blazor browser hosted application. Configured AAD then is used to access blobs in an Azure Storage Account. This approach doesn't require any secrets and opens possibilities for using it at the client side in a browser in a static web hosting environment.
Some Azure SDK-s like Azure Storage client libraries for .NET require Cryptography .Net library that is not implemented for Web Assembly. This repo contains a sample workaround using JavaScript crypto.subtle
component for getting SAS signatures for Azure Blobs. The workaround was to copy the code from the Microsoft Open Source SDK and modify it replacing System.Security.Cryptography.HMACSHA256
calls with crypto.subtle
calls. The code is located in AzureBlobStorage folder. It requires HmacSha256.js to be placed in the wwwroot
folder.
Azure Storage Static websites "as is" aren't compatible with AAD callbacks because the default Blazor framework is expected to handle dynamic authentication/login-callback
URL. As a workaround index.razor
component is extended to handle two more routes:
@page "/authentication/login-callback"
@page "/authentication/login-failed"
redirecting those requests to yet another new added route - /authentication/finalize/{action}
in the Authentication.razor
component. Setting Error document path
to be index.html
enables the entire login loop.
There is an issue with environment specific appsettings.json
and a proposed workaround. The workaround requires Visual Studio. If you use other build tool make sure that you implement the pre-build steps in some other way.
The workaround also requires the js
folder to exist. Either create it or add one more step to the build process.
if not exist "$(ProjectDir)wwwroot\js" mkdir $(ProjectDir)wwwroot\js
- Instructions below require Unix shell and were tested on Windows Subsystem for Linux (WSL).
- Azure CLI.
- Azure Storage Account.
AAD authorization in this sample is based on an AAD App Registration. You will need to create and configure the app, allow the app access to an Azure Storage Account and allow access to the account for your Azure user login.
-
Make sure you are logged in into Azure CLI by running
az login
. -
Run the script below. It will create the app, set current user as the owner and print AAD parameters for the client.
AppName={replace with desired app registration display name} AppId=`az ad app create --display-name $AppName --oauth2-allow-implicit-flow true --reply-urls https://localhost:5001/authentication/login-callback --query appId -o tsv` UserId=`az ad signed-in-user show --query objectId -o tsv` az ad app owner add --id $AppId --owner-object-id $UserId TenantId=`az account show --query tenantId -o tsv` echo Authority: https://login.microsoftonline.com/$TenantId echo ClientId: $AppId
-
Copy appsettings.json to appsettings.Debug.json in the
wwwroot
directory and update Authority and ClientId getting the values from the output of the script above. -
Open Azure Portal and select your new App Registration in the Azure Active Directory > App Registrations blade.
-
Switch to Authentication blade.
-
Find
This app has implicit grant settings enabled. If you are using any of these URIs in a SPA with MSAL.js 2.0, you should migrate URIs.
and migrate the URI-s to SPA configuration. -
Uncheck
Access tokens (used for implicit flows)
and save changes.
Start the Blazor application and make sure that it is available at https://localhost:5001/
.
Note: it may take couple of minutes before the permissions propagate.
Click Login
in the upper right corner. It should open Microsoft login popup window. Complete the login accepting the permissions request. The upper line should show your name registered with the Microsoft account. Blobs will not be available at this point and Access denied
message will appear.
The App Registration configured above will need permissions to access blobs on user's behalf. To enable it run the following script:
AzureStorageAppId=e406a681-f3d4-42a8-90b6-c2b029497af1
PermissionId=`az ad sp show --id $AzureStorageAppId --query oauth2Permissions[0].id -o tsv`
az ad app permission add --api $AzureStorageAppId --id $AppId --api-permissions $PermissionId=Scope
az ad app permission grant --id $AppId --api $AzureStorageAppId --query resourceId
az ad app permission admin-consent --id $AppId
By default users don't have permissions for accessing their own storage accounts via AAD. Add the permissions executing the script below. It will add read only permissions for the current user limited to the specified storage container.
StorageAccountName={replace with existing storage account name}
ContainerName={replace with existing container in the storage account}
StorageAccountId=`az storage account show -n $StorageAccountName --query id -o tsv`
UserPrincipalName=`az ad signed-in-user show --query userPrincipalName -o tsv`
az role assignment create --assignee $UserPrincipalName --role "Storage Blob Data Reader" --scope $StorageAccountId/blobServices/default/containers/$ContainerName --query id
az role assignment create --role "Storage Blob Delegator" --assignee $UserPrincipalName --scope $StorageAccountId --query id
To access storage from a browser enable CORS:
az storage cors add --methods GET HEAD OPTIONS POST --origins '*' --allowed-headers '*' --exposed-headers '*' --services b --account-name $StorageAccountName --max-age 3600
Update appsettings.Debug.json
in the wwwroot
directory setting storage account name and a container name in that storage account.
Restart the application and login. The list of blobs in the configured container should show up on the web page. Blobs with names ending with .jpg will be shown as images, .mp4 blobs will be shown as videos, .txt blobs will be displayed with their content and all other types will be listed as blob names. Note: it may take couple of minutes before the permissions propagate.
Note: Sometimes local build caches some files preventing the app from working if there were incompatible changes in the Azure. Deleting bin
and obj
directories will fix that particular issue.
Create appsettings.Release.json
from appsettings.json
and update similar to appsettings.Debug.json
with the release values.
Build and deploy the project according to your hosting platform.
If you are using Azure Storage Static website feature set both Index document name
and Error document path
to be index.html
.
After deploying the Application go to the Azure Portal > Azure Active Directory > App Registrations blade > Authentication blade > Single-page application section and add Redirect URI to the location corresponding to your deployment similar to existing local host setup.
For other topics, like compression optimizations see Host and deploy ASP.NET Core Blazor WebAssembly.