{"id":7871,"date":"2026-02-24T10:36:22","date_gmt":"2026-02-24T09:36:22","guid":{"rendered":"https:\/\/blog.redbaronofazure.com\/?p=7871"},"modified":"2026-03-05T16:03:40","modified_gmt":"2026-03-05T15:03:40","slug":"entra-workload-identity-federation","status":"publish","type":"post","link":"https:\/\/blog.redbaronofazure.com\/?p=7871","title":{"rendered":"Entra Workload Identity Federation"},"content":{"rendered":"\n<p>Scenarios for <a href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/workload-id\/workload-identity-federation\" data-type=\"URL\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/entra\/workload-id\/workload-identity-federation\" target=\"_blank\" rel=\"noreferrer noopener\">Entra Workload Identity Federation<\/a> includes Github Actions or apps running in Google Cloud (GCP) or AWS or other computing platforms. The traditional way of configuring authentication between those platforms and Entra would be to share an application client id and secret, or certificate, so that the external apps can authenticate with Entra. This works well but comes with the tax on lifecycle management where you have to periodically share new client secrets or certificates with the external party as they expire overtime.<\/p>\n\n\n\n<h2>Token Exchange<\/h2>\n\n\n\n<p>Entra Workload Identity Federation is a new and simpler way of solving this identity integration. Via trusting an external identity provider (IDP), such as GCP, AWS or any OIDC provider, Entra can accept an access token from these IDPs and exchange it for an Entra access token. The benefit of token exchange is that a) the external app must first authenticate with its IDP to get an access token to give Entra, and b) Entra does not have to share client secrets or certificates and do the lifecycle management of them. The possible risk with this federation is that you now trust an external identity provider to do the right thing in keeping secure. However, sharing client secret or certificate, you took the same risk in trusting that the external party kept them secure.<\/p>\n\n\n\n<h2>Entra configuration<\/h2>\n\n\n\n<p>You configure Workload Identity Federation on an App registration. This makes sense as the external app calls the Entra <a rel=\"noreferrer noopener\" href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity-platform\/v2-protocols#endpoints\" data-type=\"URL\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity-platform\/v2-protocols#endpoints\" target=\"_blank\">oauth2\/v2.0\/token<\/a> endpoint using the <a rel=\"noreferrer noopener\" href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity-platform\/v2-oauth2-client-creds-grant-flow\" data-type=\"URL\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity-platform\/v2-oauth2-client-creds-grant-flow\" target=\"_blank\">client_credentials<\/a> grant_type flow, passing the client_id of the Entra application.<\/p>\n\n\n\n<p>In the \u201cCertificates &amp; Secrets\u201d blade, there is a tab named \u201cFederated credentials\u201d. When you click \u201c+Add credential\u201d, you are presented with a drop-down of preselected federation scenarios, like Github Actions, Kubernetes, etc. For OIDC identity providers, like GCP, AWS and others, you choose \u201cOther issuer\u201d.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134101-1024x481.png\" alt=\"\" class=\"wp-image-7872\" width=\"840\" height=\"394\" srcset=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134101-1024x481.png 1024w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134101-300x141.png 300w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134101-768x361.png 768w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134101.png 1043w\" sizes=\"(max-width: 840px) 100vw, 840px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"960\" height=\"544\" src=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-135221.png\" alt=\"\" class=\"wp-image-7873\" srcset=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-135221.png 960w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-135221-300x170.png 300w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-135221-768x435.png 768w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><\/figure>\n\n\n\n<p>To accept an access token from the other IDP, you need to specify:<\/p>\n\n\n\n<ul><li>The issuer (iss)<\/li><li>The subject (sub)<\/li><li>The audience (aud)<\/li><\/ul>\n\n\n\n<p>These three values should all be in the access token as claims iss, sub and aud. If the subject claim has a different name than \u201csub\u201d you use the \u201cClaims matching expression\u201d to specify the name.<\/p>\n\n\n\n<p>Beware that the \u201cIssuer\u201d entry is not the .well-known\/openid-configuration endpoint, which would have been the more natural choice (as that endpoint tells you the issuer). Now it is inferred that there will be a .well-known\/openid-configuration endpoint behind what you specify in the \u201cIssuer\u201d entry, else the token exchange will fail when Entra tries to validate the JWT token passed.<\/p>\n\n\n\n<p>For the \u201cAudience\u201d entry, click Edit for it to open up, then enter the value your OIDC IDP has in its access token.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"971\" height=\"784\" src=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134134.png\" alt=\"\" class=\"wp-image-7874\" srcset=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134134.png 971w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134134-300x242.png 300w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134134-768x620.png 768w\" sizes=\"(max-width: 971px) 100vw, 971px\" \/><\/figure>\n\n\n\n<p>The access token generated by my test IDP provider.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"749\" height=\"437\" src=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134216.png\" alt=\"\" class=\"wp-image-7875\" srcset=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134216.png 749w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-23-134216-300x175.png 300w\" sizes=\"(max-width: 749px) 100vw, 749px\" \/><\/figure>\n\n\n\n<p>What \u201cOther\u201d OIDC providers can be added? Everything but Entra is the simple answer. You can\u2019t federate Entra with Entra.<\/p>\n\n\n\n<h2>Requested App Permissions<\/h2>\n\n\n\n<p>When the external app makes the call to Entra\u2019s token endpoint requesting the token exchange, it does this using the OIDC client_credential grant flow. It passes its access token in the client_assertion parameter. In Powershell, the call would look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Invoke-RestMethod -Method Post <code>\n -Uri https:\/\/login.microsoftonline.com\/$tenantIdEntra\/oauth2\/v2.0\/token\" \n -Body @{ \n  grant_type=\"client_credentials\"; \n  client_id=$ClientIdEntra; \n  client_assertion_type=\"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\"; \n  client_assertion=$access_token_Other; \n  scope=\"3db474b9-6a0c-4840-96ac-1fceb342124f\/.default\" <\/code>`\n }\n\n<\/code><\/pre>\n\n\n\n<p>The external app requests permissions in the scope parameter. In this case the Entra application has the permission to call the Entra Verified ID API (3db474b9-6a0c-4840-96ac-1fceb342124f) and the external app requests that permission. Other example scopes could be https:\/\/graph.microsoft.com\/.default for access to Microsoft Graph, https:\/\/management.azure.com\/.default for access to managing Azure resources.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"756\" height=\"230\" src=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-24-093957.png\" alt=\"\" class=\"wp-image-7876\" srcset=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-24-093957.png 756w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-24-093957-300x91.png 300w\" sizes=\"(max-width: 756px) 100vw, 756px\" \/><\/figure>\n\n\n\n<h2>Sign-in Log Events<\/h2>\n\n\n\n<p>In Entra\u2019s sign-in logs, there will be an event entry in the \u201cService principle sign-ins\u201d tab. If you inspect the details, you will see that it says \u201cFederated identity credential\u201d for the type.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" width=\"619\" height=\"207\" src=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-24-100529.png\" alt=\"\" class=\"wp-image-7877\" srcset=\"https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-24-100529.png 619w, https:\/\/blog.redbaronofazure.com\/wp-content\/uploads\/2026\/02\/Screenshot-2026-02-24-100529-300x100.png 300w\" sizes=\"(max-width: 619px) 100vw, 619px\" \/><\/figure>\n\n\n\n<p>The Federated credential ID is the identity of the configuration and you can inspect it via Graph API to back track which app and federation was used.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"javascript\" class=\"language-javascript\">GET \/applications(appId='{appId}')\/federatedIdentityCredentials<\/code><\/pre>\n\n\n\n<h2>AWS outbound identity federation<\/h2>\n\n\n\n<p>If you want to try this with AWS, you can follow their <a rel=\"noreferrer noopener\" href=\"https:\/\/aws.amazon.com\/blogs\/aws\/simplify-access-to-external-services-using-aws-iam-outbound-identity-federation\/\" target=\"_blank\">blog<\/a> about how to set up outgoing identity federation in AWS.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Scenarios for Entra Workload Identity Federation includes Github Actions or apps running in Google Cloud (GCP) or AWS or other computing platforms. The traditional way of configuring authentication between those platforms and Entra would be to share an application client id and secret, or certificate, so that the external apps can authenticate with Entra. This [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[453],"tags":[455,454],"_links":{"self":[{"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=\/wp\/v2\/posts\/7871"}],"collection":[{"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7871"}],"version-history":[{"count":8,"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=\/wp\/v2\/posts\/7871\/revisions"}],"predecessor-version":[{"id":7891,"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=\/wp\/v2\/posts\/7871\/revisions\/7891"}],"wp:attachment":[{"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7871"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7871"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.redbaronofazure.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7871"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}