---
cuppy_hub: azure
cuppy_path: reference/entra/federated-credential-errors.md
cuppy_section: docs
cuppy_doc: BENQ-6PRT
cuppy_doc_uuid: 07c8bdf7-4bdf-4c1f-9c85-9932dd2e8007
cuppy_permalink: https://cuppy.io/azure/d/BENQ-6PRT
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/azure/docs/reference/entra/federated-credential-errors
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 9ba8ef19d1a363b3350a8b7cd22f3d3d354805d9a9b364069dcb7e0589cf9a5b
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Federated identity credential errors

**A federated credential trusts an external token when four values match exactly: `issuer` = the token's `iss`, `subject` = its `sub`, one of `audiences` = its `aud`, and the token is signed RS256.** Matching has been **case-sensitive** since September 2024, wildcards aren't allowed (except in preview *flexible* credentials), and a wrong value saves without complaint: the error appears only at token exchange.

**The check for every row:** put the presented claims next to the credential.

- **Presented claims.** `azure/login` prints them in the run log under `Federated token details:` (`issuer`, `subject claim`, `audience`, `job_workflow_ref`). The AADSTS700213 message also quotes the subject. Elsewhere, decode the external token's payload.
- **Credential on an app:** `az ad app federated-credential list --id <client-id>`.
- **Credential on a user-assigned managed identity:** `az identity federated-credential list --identity-name <name> --resource-group <rg>`.

## Errors

| Error | Cause → fix | Check |
|---|---|---|
| `AADSTS70021: No matching federated identity record found for presented assertion.` | (1) The credential was **just created**: it takes minutes to propagate, so wait and retry, and keep retry logic on token requests. (2) No credential on this app or identity matches at all: wrong client ID in the workflow | The list call: is there a credential with this issuer? Is `AZURE_CLIENT_ID` the app or identity that holds it? |
| `AADSTS700211: No matching federated identity record found for presented assertion issuer …` | The credential's `issuer` differs from the token's `iss`. GitHub's is `https://token.actions.githubusercontent.com` (one Learn page shows a trailing slash; the configuration rule and examples don't). Leading or trailing whitespace blocks the exchange. On AKS identity bindings, set `enableAzureProxy: true` on `WorkloadIdentityCredential` (AKS child hub) | `issuer` in the list output vs the token's `iss` |
| `AADSTS700212: No matching federated identity record found for presented assertion audience '…'` | The token's `aud` isn't in the credential's `audiences`. Use `api://AzureADTokenExchange` on both sides; `azure/login`'s `audience` input defaults to it | `audiences` vs the token's `aud` |
| `AADSTS700213: No matching federated identity record found for presented assertion subject '<sub>'. Please note that matching is done using a case-sensitive comparison. …` | The subject differs. See **Subjects** below: environment vs branch, pull request, tag, and the immutable format | The quoted `<sub>` vs each credential's `subject` |
| `AADSTS7002138: … The subject matches with case-insensitive comparison, but not with case-sensitive comparison.` | Only the casing differs (organization, repository, branch or environment name). Copy the subject from the run log exactly | Same comparison, character by character |
| `AADSTS700229` ForbiddenTokenType | A credential that trusts a **Microsoft Entra** issuer (an app trusting a managed identity) was given a user-delegated token. Only app-only tokens are accepted | How the presented token was obtained: it must come from a client-credentials (app-only) flow, so it carries no `scp` claim |
| `AADSTS700021` | Self-made client assertion: its `sub` and `iss` must both equal the client ID | Decode your JWT |
| `AADSTS700023` | Client assertion `aud` must be `https://login.microsoftonline.com/<tenant-id>/v2` (as the SDK guide states it) | Decode your JWT |
| `AADSTS50027` | The JWT assertion is malformed | Decode it; three base64url parts |
| `Failed to fetch federated token from GitHub. Please make sure to give write permissions to id-token in the workflow.` | The job can't request an OIDC token. Add `permissions: id-token: write` (and `contents: read`) at workflow or job level | The workflow's `permissions` block for that job |
| HTTP **409 Conflict** creating credentials | Several credentials created **concurrently on one user-assigned identity**. Create them serially (`dependsOn`, or a serial copy loop; Terraform `azurerm` ≥ 3.40.0 does this) | Did the deployment create them in parallel? |
| Can't add another credential | The limit is **20** per app or user-assigned identity. Use GitHub environments to share one subject, or a flexible credential (preview) | Count the list output |

## Subjects (GitHub Actions)

GitHub's `sub` depends on how the job runs (Learn, "Configure an app to trust an external identity provider"):

| The job… | `sub` |
|---|---|
| declares `environment: production` | `repo:<org>/<repo>:environment:production` — the environment wins over the branch |
| runs on a `pull_request` event | `repo:<org>/<repo>:pull-request` |
| runs on a branch push | `repo:<org>/<repo>:ref:refs/heads/<branch>` |
| runs on a tag push | `repo:<org>/<repo>:ref:refs/tags/<tag>` |

**Immutable subjects (GitHub.com, 2026):** GitHub can put the owner and repository IDs in the subject: `repo:<org>@<org-id>/<repo>@<repo-id>:ref:refs/heads/main`. **Repositories created after July 15, 2026, and any repository renamed or transferred after that date, use it automatically; older repositories only after opting in.** So AADSTS700213 now has two new causes:

- A new or renamed repository presents the **immutable** subject, and the credential holds the **name-based** one. Add a credential with the subject from the run log.
- The credential was made in the portal with the optional owner and repository ID fields filled in (immutable format), but the repository hasn't opted in and still presents the **name-based** subject (Azure/login troubleshooting).

Migrating without downtime: add the new credential beside the old one, opt the repository in, run the workflow, then `az ad app federated-credential delete --id <client-id> --federated-credential-id <old-id>`. Not available on GitHub Enterprise Server. Flexible credentials for GitHub must match `sub` **and** `repository_id` or `repository_owner_id`.

## When none of these fits

Compare all four claims, not just the subject, and confirm which client ID the workflow sends. If the error names no claim, wait several minutes after any credential change and retry before changing anything else. Setup from scratch: `guides/entra/github-actions-oidc.md`; non-federated token errors: `reference/entra/errors.md`.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 107 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/azure/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
