A Secure Blazor Server Azure Deployment Pipeline




I wanted to kick off the year with something practical, modern, and production-ready. This post is based on my own experience deploying my new website, dotnetconsult.tech, using GitHub Actions into Azure App Service.

In this post, I’ll walk through how to set up a secure development and deployment flow using:

This approach avoids stored secrets entirely and reflects how I now set up every new .NET project whether it’s for a client, a SaaS product, or an internal tool.


Why OpenID Connect (OIDC)?

  • ✅ No publish profiles

  • ✅ No long-lived secrets

  • ✅ Short-lived tokens issued per deployment

  • ✅ Azure-managed access control

  • ✅ Enterprise-ready and future-proof

If you’re still using publish profiles or service principal secrets, this is the upgrade path.

Prerequisites

Before starting, you’ll need:


Step 1 - Create the Blazor Server app

I’m going to be using Visual Studio 2026, and we’ll start by creating a new project.

Select "Blazor Web App".

I named the project BlazorAzureGitHubPipelinePost and stored it in my usual development directory on my machine.

For this demonstration, I’m leaving all the default settings unchanged. Click Next, then Create.


Once the project is created, run the application to confirm everything works as expected.



Now that the simple Blazor app is up and running, let’s get it committed to GitHub.


Step 2 — Push the project to GitHub

Because this is a brand-new project that hasn’t been added to source control yet:

  • Right-click the solution

  • Select Create Git Repository…



In the Create a GitHub repository dialog:
  • Select GitHub as the remote repository

  • Choose whether the repository should be Public or Private

  • Confirm or update the repository name

  • Optionally add a README

  • Click Create and Push

We’ve now created our sample application, set up a GitHub repository, and pushed the initial code.
Next, we’ll move on to publishing the application to Azure.

Step 3 - Create the Azure App Service

  • Open a browser and go to portal.azure.com

  • In the search bar, type App Services

  • Select App Services under Services




  • Click Create → Web App

On the Basics tab, configure the following:

  • Subscription: Select your Azure subscription

  • Resource Group:

    • Choose an existing one, or

    • Click Create new

  • Name: Enter a unique app name

    • This becomes your URL: https://<name>.azurewebsites.net


  • Publish: Code

  • Runtime stack: .NET 10 (LTS)

  • Operating System: Linux (Windows is also fine)

  • Region: Choose the closest region

Pricing plan

  • Select an existing App Service Plan, or

  • Create a new one

For demos and testing, Free (F1) or Basic is sufficient.

Click Review + Create, then Create.

Once deployment completes, click Go to resource.

You’ll now see the App Service overview page, including:

  • Application URL

  • Status (Running)

At this point, the App Service is ready to receive deployments from GitHub Actions.


Step 4 — Create an Entra ID App Registration (OIDC)

To allow GitHub Actions to deploy securely to Azure without storing secrets, we’ll use OIDC federation between GitHub and Microsoft Entra ID.

In the Azure Portal, search for "App registration", and click "New Registration"

Configure the app: 
  • Name e.g. "github-actions-blazorsecureapp"
  • Supported account types: Select Accounts in this organizational directory only
  • Redirect URI: Leave this blank
Click Register

Once created, make a note of: 
  • Application (client) ID
  • Directory (tenant) ID

Your app registration needs permission to deploy to Azure

Navigate to your App Service, and select "Access control (IAM)", Click "Add" > "Add Role assignment"


Select the "Privileged administrator roles" tab.


In the Search box, search for the role "Contributor" or (Website contributor for tighter scope)

Select the "Contributor" role from the list and click "Next"

Assign access to : User, group or  service principal

Click the "+ Select Members" and select your App Registration name, click "Select"


Click "Review + assign", this grants the app permission to deploy your application. 

Step 5 — Assign permissions to Azure

To allow GitHub actions to authenticate without secrets, we have to add a federated identity (OIDC) to our App Registration.

Go back to your App Registration

Select "Certificates & Secrets"

Open the "Federated credentials" tab

Click "Add credential"


Fill in the following:

  • Federated credential scenario:
    GitHub Actions deploying Azure resources

  • Organization:
    Your GitHub organization or username

  • Repository:
    Your repository name

  • Entity type:
    Branch

  • GitHub branch name:
    main (or whichever branch triggers deployment)

  • Name:
     github-main-branch-deploy

Click "Add".


Step 6 — Configure GitHub repository variables


To allow GitHub Actions to authenticate with Microsoft Azure, we need to store a few values securely as GitHub repository secrets.

These secrets will be used by the workflow at runtime and are never exposed in logs.

From your Microsoft Entra ID App Registration and Azure subscription, gather the following:

  • Application (Client) ID

  • Directory (Tenant) ID

  • Azure Subscription ID

Open Repository Settings

Open your repository on GitHub, Click Settings.

In the left-hand menu, expand Secrets and variables Select Actions


Add the Azure Secrets

Click New repository secret, Create the following secrets one by one:

Secret 1: AZURE_CLIENT_ID

  • Name: AZURE_CLIENT_ID

  • Value: Application (client) ID from the App Registration

  • Click Save secret


Secret 2: AZURE_TENANT_ID


Secret 3: AZURE_SUBSCRIPTION_ID

What These Secrets Are Used For

These secrets are referenced in your GitHub Actions workflow to:

  • Authenticate to Azure using OIDC

  • Select the correct tenant and subscription

  • Deploy your application to the correct App Service

No passwords or client secrets are required.

Step 7 — GitHub Actions workflow (OIDC)

The easiest way to have found to create the YAML file needed from your deploy is to head back to visual studio, and create a new Publish profile.

In Visual Studio, Right click on your project and select "Publish".

Click "Add a publish profile" if the dialog does not automatically popup.

Select "Azure", Click "Next"

Select "Azure App Service (Linux)", Click Next.

Note: If you provisioned your App Service to be windows you will need to select "Azure App Service (Windows) "
Select the App Service you created in Azure. Click Next.

Select "CI/CD workflows(generates yml file)"



Click "Finish"

We now need to setup our variables in the yml file, before we push these changes to the master branch

Before pushing, open the generated .yml file and update:
with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

Commit and Commit All and Push.


Soon as you push any changes it should run the action and deploy to Azure. 

Step 8 — Deploy

So to check the deployment is working correctly lets connect to the repository in GitHub and select the "Action" tab.


You should see 1 Workflow has ran and been successful.

All looking good up to now. So the final check is to head over to our app service and check our blazor app is up and running. 



What I’ll cover next

In upcoming posts on dotnetconsult.tech, I’ll be expanding this deployment pipeline into a full multi-environment setup, including:

  • Deploying to Azure App Service deployment slots (Dev, QA, Production)

  • Managing environment-specific configuration and app settings

    • Ensuring variables are scoped correctly per environment

    • Preventing configuration leakage between environments

  • Using GitHub Actions environments to control deployments

  • Implementing branch protection and promotion workflows:

    • Pull requests from Dev → QA

    • Pull requests from QA → Production

    • Production deployments only ever coming from QA

    • QA deployments only ever coming from Dev

  • Enforcing approval gates and checks before production releases

  • Designing CI/CD pipelines that reflect real-world enterprise release flows

The goal is to move from a single pipeline to a safe, auditable, and repeatable promotion model that scales from side projects to enterprise systems.

Final thoughts

Starting the year with a secure, modern deployment pipeline sets the tone for everything that follows.

If you’re building serious .NET applications in 2026, OIDC-based GitHub Actions + Azure should be your default.

If this article sparked ideas, raised questions, or you’d like to discuss how these concepts apply to your own projects, feel free to reach out via dotnetconsult.tech. I’m always happy to chat about real-world .NET architecture, performance, and design decisions.

Comments

Popular posts from this blog

Stop Wrapping EF Core in Repositories: Use Specifications + Clean Architecture

Using a Semantic Model as a Reasoning Layer (Not Just Metadata)