Automate Azure B2C redirect url


As many others, I run tests on my apps before deploying them to production, one kind of tests are the e2e tests written in Cypress.

And for these to run, I need to be able to login with a test user. I’ll get back to how exactly I do that with Cypress in another blog post, but I do it with UI and saving a session as per Cypress own documentation.

But this created a new problem, now any stage environments that Azure Static Web App spins up needs to be a redirect url for my Azure AD B2C that handles the users.

Setting upp Azure B2C

Well, Google to the rescue. Thanks to this GitHub issue, https://github.com/Azure/static-web-apps/issues/992 I got pointed in the right direction, but the answer provided there wasn’t complete. Back, to Google. Thankfully Microsofts documentation come with solutions quickly.

I followed this guide, https://learn.microsoft.com/en-us/azure/active-directory-b2c/microsoft-graph-get-started?tabs=app-reg-ga to create an application that Github Actions could use to authenticate against Azure, giving it the right premissions (those are found in the documentation here, https://learn.microsoft.com/en-us/graph/api/application-update?view=graph-rest-1.0&tabs=http)

Setting up B2C

Following the guide found at https://learn.microsoft.com/en-us/azure/active-directory-b2c/microsoft-graph-get-started?tabs=app-reg-ga in all the steps, using the B2C tenant you want to work with. Remember to save the client secret in the last step of the guide to use in the next step here.

To check if it works, you can use https://developer.microsoft.com/en-us/graph/graph-explorer/ to test. And if you need to switch from your default tenant of your Microsoft account, add a query variable like so, https://developer.microsoft.com/en-us/graph/graph-explorer?tenant=YOUR_TENANT.onmicrosoft.com

Setting up GitHub Secrets

With B2C set up to be able to accept a login from an app, time to save the data needed for GitHub in GitHub secrets and variables. I use environments to be able to shift depending on where I’m doing it, leaving some data global to the repository.

In secrets for my Stage environment, adding AZURE_B2C_CREDENTIALS containing a Json object, as follows:

{
clientId:"B2C_CLIENT_ID",
clientSecret:"B2C_CLIENT_SECRET",
subscriptionId:"B2C_SUBSCRIPTION_ID",
tenantId: "B2C_TENANT_ID"
}

Where you replace the values B2C_CLIENT_ID and the rest with your values from the B2C client you use along with the client secret created in the previous step.

Next we need the application Id for the client in B2C, this is not the client id found in the UI, you need to use https://graph.microsoft.com/v1.0/applications and find the application you want to update with the new url in the list, and get the application id. Save this Id as a secret in GitHub as B2C_APP_ID for the environment used (Stage in the code further down)

Application URL

In my workflow, this is a step after publication of the app, meaning I have the generated url saved and is given it as an input from the previous step. However, you can construct it as:

$appUrl = "https://${{ vars.STATIC_WEB_APP_URL }}-${{ github.event.pull_request.number }}.${{ vars.STATIC_SITE_REGION }}.1.azurestaticapps.net"

Where you then need to save the variables STATIC_WEB_APP_URL and STATIC_SITE_REGION for your static web app.

STATIC_WEB_APP_URL is the the xx part of xx.1.azurestaticapps.net of my Static Web App’s generated url.

STATIC_SITE_REGION is in lowercase, the region chosen for the static web app when it was created.

Updating GitHub Workflow

Okay, ready to write the workflow using what we have preparted. Since I mostly use reusable workflows, I added a new one that I called setup-b2c.yml in my workflows folder.

And wrote it as following:

name: Add app url to B2C app for testing
on:
  workflow_call:
    inputs:
      appUrl:
        type: string
        required: true
      environment:
        type: string
        required: true
    secrets:
      AZURE_B2C_CREDENTIALS:
        required: true

jobs:
  update-b2c:
    name: Update B2C Redirect URIs
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - name: Login to Azure
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_B2C_CREDENTIALS }}
          allow-no-subscriptions: true
          enable-AzPSSession: true
      - name: Update B2C Redirect URIs
        uses: azure/powershell@v1
        with:
          inlineScript: |
            $appId= "${{ secrets.B2C_APP_ID }}"
            $appUrl = "${{ inputs.appUrl}}"
            $apiUrl = "https://graph.microsoft.com/v1.0/applications/" + $appId
            $apiUrlSpaFilterd = $apiUrl  + "?$select=spa"
            $appUris = az rest --method GET --uri $apiUrlSpaFilterd | ConvertFrom-Json
            $newUris = @{'spa' = $appUris.spa}
            if ( -not ($newUris.spa.redirectUris -contains $appUrl)) {
              $newUris.spa.redirectUris += $appUrl
            }
            $newUrisJson = $newUris | ConvertTo-Json -Compress
            $newUrisJson = $newUrisJson -replace '([\\]*)"', '$1$1\"'
            az rest --method PATCH --uri $apiUrl --headers 'Content-Type=application/json' --body $newUrisJson
          azPSVersion: "latest"

The magic happens in a PowerShell script for Azure, first loading the spas urls already registered, and if it doesn’t, creates a new string where the app’s url is added on and then it is updated at the B2C client with a http Patch call.

And with that it is done, obviously I had to wire up my main file to use the workflow, but that was simply adding a job like this:

setup-b2c:
    uses: ./.github/workflows/setup-b2c.yml
    needs: deploy
    secrets: inherit
    with:
      appUrl: ${{ needs.deploy.outputs.appUrl }}
      environment: Stage

Inspiration

UPDATE

A few months back I ran into a problem with with logging in using the client secret, giving me the error “The subscription of ‘xxx’ doesn’t exist in cloud ‘AzureCloud’.

After way more time than I want to admit, I solved it by setting up the Authentication App in B2C to use Federated Credentials towards Github and ran it with that instead successfully. Meaing I had to update the yaml in the setup-b2c.yml to

name: Add app url to B2C app for testing
on:
  workflow_call:
    inputs:
      appUrl:
        type: string
        required: true
      environment:
        type: string
        required: true
    secrets:
      AZURE_B2C_CREDENTIALS:
        required: true

jobs:
  update-b2c:
    name: Update B2C Redirect URIs
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - name: Login to Azure
        uses: azure/login@v1
        with:
          client-id: ${{ secrets.AZURE_B2C_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_B2C_TENANT_ID }}
          allow-no-subscriptions: true
          enable-AzPSSession: true
      - name: Update B2C Redirect URIs
       ... As before

Where, you guessed it AZURE_B2C_CLIENT_ID and AZURE_B2C_TENANT_ID are new reposisitory secrets representing the authentication client id and tenant from Azure.


Leave a Reply

Your email address will not be published. Required fields are marked *