Thumbnail Release Branch Strategies in CI/CD with Federated Identity - GitHub edition

Release Branch Strategies in CI/CD with Federated Identity - GitHub edition

I recently wrote a blog post on using federated identity with GitHub Actions to deploy artifacts to Microsoft 365 using the CLI for Microsoft 365. It’s a f-a-n-t-a-s-t-i-c feature which brings an easier and more secure auth experience to all who work with CI/CD automation. But what if you’re like me, and you’re working with release branch strategies which are advised by Microsoft?

So you’ve become enthousiastic about using Federated Identity, either by reading my own blog post about this, or maybe by reading the one posted by Andrew Connell, which is an excellent read by the way! 👏

So you’ve started checking out what federated identity can give you. And it’s a lot! It brings ease of configuration, no more messing with certificates. A sense of security because you don’t need to be afraid these certificates are leaked. And one less item on your IT Administration todo list, because these credentials do not expire.

👏 Awesome, right?

So you look at the features for configurating federated credentials in Entra ID, and you discover that there are quite some to choose from:

github-federated-identity-options

You could allow deployments from a certain environment, branch or tag or for pull requests. You could allow authentication with the Entra ID App only if the GitHub Action is authenticating from the main branch. Or if it’s authenticating from the Production GitHub Environment that you might have created. This is fantastic, and it brings some extra security to make sure you only deploy to production from the right CI/CD Build & Deploy runs. I mean, it would be bad if a merged pull request to a dev branch would end up on production, right? You need that extra bit of security on the side of Entra ID. You don’t want to trust the people who configure the GitHub Actions, as those are the developers. They’re not necessarily interested in the security of it all. (And I’m a dev, so I know all about that… 😉)

However, there are some downsides to these features. For example:

  1. For environments - How can we actually be sure that the right build is deployed to the Production GitHub environment? We simply have to trust the developers that they’ve configured the build pipeline correctly.
  2. For branches - You’ll need to select a single branch in Entra ID… but you may have a release strategy in place where you create a release branch for every new release. You don’t want update the Entra ID App on every release.
  3. For tags - You’ll need to select a single tag in Entra ID… but releasing based on tags often means that a new tag is created for every new release. You don’t want update the Entra ID App on every release.
  4. For Pull Requests - What if you’re release strategy is not directly related to pull requests? You may only release a set of fixes after several pull requests have been merged.

Those features are great… but you happen to not use environments today, and tags are too limiting here. You’ve made a decision a while back to use release branches as an effective and solid branching strategy. Maybe you’ve even followed Microsofts guidance on this.

So for every release you create a release branch, like this: releases/release-17-may-2025, releases/release-v1.12.2, or something similar. And you include the commits on that branch that you want to deploy to production. It’s a very solid way of working.

❓ So how can we incorporate that into our setup with Federated Identity? How can we only deploy our SPFx application to the production app catalog if the build is run on a release branch? How can we make sure that happens from the side of Entra ID? We can’t use the default setup with a branch filter on the subject. Because we’d need to update our Entra ID app federated credential for every deployment, and that’s unmanageable.

Fortunately there is a way of working that will satisfy our requirement! It is in preview, but it’s working! And it’s called Flexible Federated Identity Credentials.

Note: Flexible Federated Identity credentials are in preview, and currently only work for a couple of services, like GitHub. Azure DevOps is not supported yet.

So to rehash the idea of Federated Identity, this is what happens: When running a GitHub Action, GitHub goes through an OIDC flow, requesting an Access Token from Entra ID, called a federation token, with a specific issuer, subject and audience value. The subject of the federation token will contain information about the organisation, repository, environment and branch where the Action is running. The CLI for Microsoft 365 (or any other tool) running within the GitHub Action pipeline, may use that federation token and send it to Entra ID to swap it for an access token for another service, like the Microsoft Graph. Entra ID will verify that the token contains the correct information, based on the federated credential that’s been configured in the App Registration. If that verification succeeds, it will return an access token to the CLI for Microsoft 365 running in the GitHub action.

So now we get to the gist of it. Flexible Federated Identity credentials make it possible to write a matching expression to verify whether the incoming federation token has a specific claim or even a couple of claims:

github-flexible-federated-identity-example

To make it work you have to select “Other issuer” as the Federated credential scenario. For the values you’ll have to manually paste in the expected issuer of the Federation token and write a matching expression.

So for my setup with release branches, this is what I do:

  • Issuer: https://token.actions.githubusercontent.com (This is a fixed value for GitHub)
  • Type: Claims matching expression
  • Value: claims['sub'] matches 'repo:martinlingstuyl/FederatedIdentityTest:ref:refs/heads/releases/*'

The matching expression is rather flexible, you can even use and and or operators to do multiple checks on the claims in the access token. Do checkout the documentation to find out what you can do with it!

As you can see I’ve configured the claims matching expression to check the sub claim of the incoming federation token. It should match the value written out, containing my organisation name, repo name and the branches that we want to include, with an * to indicate any value may follow.

This matching expression will make sure builds run on any of the following branches may authenticate to Entra ID: releases/release-17-may-2025, releases/release-v1.12.2.

Note: If you want to know the exact claims the federation token contains, I did not find it online, but I did log the federation token to the github action logs to decrypt it locally. Not exactly secure, so do not do that on Production repositories. 😉 If you happen to find the documentation about this, do let me know...

So in my GitHub repo, I’ve got a build pipeline running that will authenticate to Entra ID to deploy an SPFx app. I’ll not show the entire yaml, but it might be something like this:

- name: 'Connect using Federated Identity'
  run: |
    m365 login --authType federatedIdentity --appId <some-appId> --tenant <some-tenantId>    
- name: Deploy SPFx app
  run: |
    m365 spo app add --filePath <some-spfx-solution-sppkg-path> --overwrite
    m365 spo app deploy --name <some-spfx-solution-sppkg-name> --appCatalogScope 'tenant'    

Now I can run that GitHub Action on a release branch without the correct Entra ID federated credential configured, and it will throw an error:

github-action-run-failure

So what’s the error on the failed run? It’s this:

AADSTS7002131: No matching federated identity record found for presented assertion subject 'repo:martinlingstuyl/FederatedIdentityTest:ref:refs/heads/releases/release-june-2025' or no federated identity credential expression matched. Please check your federated identity credential Subject, Expression, Audience and Issuer against the presented assertion. https://learn.microsoft.com/entra/workload-id/workload-identity-federation

Now I configure the mentioned claims matching expression in Entra ID, and the result is:

github-action-run-success

✅ And that’s it. An interesting trick, isn’t it?

With this setup it’s now possible to make sure your SPFx solution can only be deployed by the CLI for Microsoft if it’s built from a release branch, keeping your releases up to your defined standards. You could even combine this with branch protection rules in GitHub to make sure not just anyone can create or commit to release branches.

🚀 Happy coding!


auth cli-microsoft365 entraid

More

More blogs

Deploying to Microsoft 365 using the CLI and federated identity - DevOps edition
Deploying to Microsoft 365 using the CLI and federated identity - DevOps edition

Learn how to properly deploy artifacts from Azure DevOps Pipelines to Microsoft 365 using the CLI for Microsoft 365 without fiddling with certificates or user credentials.

Read more
Deploying to Microsoft 365 using the CLI and federated identity - GitHub edition
Deploying to Microsoft 365 using the CLI and federated identity - GitHub edition

Learn how to properly deploy artifacts from GitHub workflows to Microsoft 365 using the CLI for Microsoft 365 without fiddling with certificates or user credentials.

Read more
Finding the minimal Azure Function authentication setup
Finding the minimal Azure Function authentication setup

Using the built-in authentication for Azure Functions is powerful, as long as you optimize it a bit!

Read more

Thanks

Thanks for reading

Thanks for reading my blog, I hope you got what you came for. Blogs of others have been super important during my work. This site is me returning the favor. If you read anything you do not understand because I failed to clarify it enough, please drop me a post using my socials.


Warm regards,
Martin

Microsoft MVP | Microsoft 365 Architect

Microsoft MVP horizontal