{
  "schemaVersion": "1.0",
  "code": "7002138",
  "name": null,
  "title": "AADSTS7002138: Federated credential subject differs in case (fix)",
  "url": "https://brambrinkmeier.com/entra/aadsts/7002138/",
  "alternates": {
    "markdown": "https://brambrinkmeier.com/entra/aadsts/7002138.md",
    "json": "https://brambrinkmeier.com/api/aadsts/7002138.json",
    "html": "https://brambrinkmeier.com/entra/aadsts/7002138/"
  },
  "description": "AADSTS7002138: the federated credential subject matches only if case is ignored. Matching is case-sensitive since 2024. Fix the casing. With KQL.",
  "summary": "AADSTS7002138 means the subject in a workload's external token matches a federated identity credential only when letter case is ignored. Since Microsoft's 2024 change, matching is case-sensitive, so the exchange fails. Typical case: a GitHub environment named Production while the credential says production. A configuration error with low attack value.",
  "inMicrosoftReference": false,
  "unlistedChecked": "2026-10-30",
  "meaningText": "Microsoft's [error code reference](https://learn.microsoft.com/entra/identity-platform/reference-error-codes) doesn't list AADSTS7002138 (checked 30 October 2026). The README of Microsoft's `Azure/login` GitHub Action documents it in its troubleshooting section:\n\n> Error: AADSTS7002138: No matching federated identity record found for presented assertion subject 'repo:&lt;org&gt;/&lt;repo&gt;:ref:refs/heads/main'. The subject matches with case-insensitive comparison, but not with case-sensitive comparison.\n\nA user on Microsoft Q&A posted the full response, which goes on:\n\n> …Check your federated identity credential Subject, Audience and Issuer against the presented assertion. See documentation at: https://learn.microsoft.com/entra/workload-id/workload-identity-federation. See breaking change notification and remediation at: https://learn.microsoft.com/en-us/entra/identity-platform/reference-breaking-changes#august-2024.\n\nThe breaking change it points to: in August 2024 Microsoft announced that federated identity credential `issuer`, `subject` and `audience` values are matched case-sensitively, where they used to be matched case-insensitively. Microsoft's invalid example:\n\n- Token subject: `repo:contoso/contoso-org:ref:refs/heads/main`\n- FIC subject: `repo:Contoso/Contoso-Org:ref:refs/heads/main`\n\nThe notice rolled the change out in stages: first to apps and managed identities created after 14 August 2024, then to inactive ones from 27 September 2024, and *\"For active applications, case-sensitive matching comes at a later date to be communicated.\"* That explains setups that ran for years and then broke with no change on your side.\n\nOur reading: 7002138 is a more specific form of [700213](https://brambrinkmeier.com/entra/aadsts/700213/). The notice itself said the 700213 message would be revamped to mention case. 7002138 goes further and tells you case is the *only* difference. Microsoft doesn't document whether there are matching codes for issuer or audience that differ only in case; the case-only codes we found all concern the subject. See [70021](https://brambrinkmeier.com/entra/aadsts/70021/) for the general no-match code and [700211](https://brambrinkmeier.com/entra/aadsts/700211/) and [700212](https://brambrinkmeier.com/entra/aadsts/700212/) for issuer and audience.",
  "sections": [
    {
      "heading": "What does AADSTS7002138 mean?",
      "text": "Microsoft's [error code reference](https://learn.microsoft.com/entra/identity-platform/reference-error-codes) doesn't list AADSTS7002138 (checked 30 October 2026). The README of Microsoft's `Azure/login` GitHub Action documents it in its troubleshooting section:\n\n> Error: AADSTS7002138: No matching federated identity record found for presented assertion subject 'repo:&lt;org&gt;/&lt;repo&gt;:ref:refs/heads/main'. The subject matches with case-insensitive comparison, but not with case-sensitive comparison.\n\nA user on Microsoft Q&A posted the full response, which goes on:\n\n> …Check your federated identity credential Subject, Audience and Issuer against the presented assertion. See documentation at: https://learn.microsoft.com/entra/workload-id/workload-identity-federation. See breaking change notification and remediation at: https://learn.microsoft.com/en-us/entra/identity-platform/reference-breaking-changes#august-2024.\n\nThe breaking change it points to: in August 2024 Microsoft announced that federated identity credential `issuer`, `subject` and `audience` values are matched case-sensitively, where they used to be matched case-insensitively. Microsoft's invalid example:\n\n- Token subject: `repo:contoso/contoso-org:ref:refs/heads/main`\n- FIC subject: `repo:Contoso/Contoso-Org:ref:refs/heads/main`\n\nThe notice rolled the change out in stages: first to apps and managed identities created after 14 August 2024, then to inactive ones from 27 September 2024, and *\"For active applications, case-sensitive matching comes at a later date to be communicated.\"* That explains setups that ran for years and then broke with no change on your side.\n\nOur reading: 7002138 is a more specific form of [700213](https://brambrinkmeier.com/entra/aadsts/700213/). The notice itself said the 700213 message would be revamped to mention case. 7002138 goes further and tells you case is the *only* difference. Microsoft doesn't document whether there are matching codes for issuer or audience that differ only in case; the case-only codes we found all concern the subject. See [70021](https://brambrinkmeier.com/entra/aadsts/70021/) for the general no-match code and [700211](https://brambrinkmeier.com/entra/aadsts/700211/) and [700212](https://brambrinkmeier.com/entra/aadsts/700212/) for issuer and audience."
    },
    {
      "heading": "Reproduced in the lab",
      "text": "On 30 October 2026 an automated lab run set this up in my own tenant: one app registration presents its access token as a client assertion, and a second app carries the federated identity credential that is supposed to accept it. With the credential's subject set to the **same value in different capitals**, Entra returned `AADSTS7002138` rather than 700213:\n\n> AADSTS7002138: No matching federated identity record found for presented assertion subject '<subject>'. The subject matches with case-insensitive comparison, but not with case-sensitive comparison.\n\nThat confirms the split in practice: a subject that is wrong gives [700213](https://brambrinkmeier.com/entra/aadsts/700213/), and a subject that is right apart from capitals gives this code. If you see 7002138, the value is correct and only the case is off, which is usually an environment name such as `Production` against `production`.\n\nThe sign-in log row isn't captured yet; see [how pages are checked](https://brambrinkmeier.com/methodology/)."
    },
    {
      "heading": "Is it an attack?",
      "text": "No. Entra found a credential that would have matched before the 2024 change. The fix is the casing.\n\n| Pattern | Likely meaning |\n|---|---|\n| A GitHub workflow uses `environment: Production` and the error shows `:environment:Production` | The credential says `production`, or the other way round. On the Q&A thread, the top answer fixed it by renaming the environment to lowercase. Microsoft's notice gives the same advice for Azure App Service users. |\n| The org or repo name has capitals | GitHub sends the casing it holds. The README: uppercase characters in the org, repo, branch or environment name must match the `subject claim` in the run log. |\n| Deployments broke without anyone changing the workflow | The staged rollout above reached your app. |\n| It still fails after \"fixing\" the case | Users report puzzling cases where the subject looks identical (Azure/login issue 573). Copy the subject from the log rather than retyping it. |"
    },
    {
      "heading": "How do I find it in my logs (KQL)?",
      "text": "Microsoft doesn't document which sign-in table 7002138 lands in. Our reading: app registration failures land in `AADServicePrincipalSignInLogs`; a user-assigned managed identity may log in the managed identity sign-in log instead. Check:\n\n```kusto\nunion withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7002138\" or ResultSignature == \"7002138\"\n| summarize Rows = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceTable\n```\n\nTo catch every app hit by the case change, list both codes together. If `ResultDescription` holds the returned message (our assumption; check a row), it shows the subject with the casing the token used:\n\n```kusto\nAADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType in (\"7002138\", \"700213\") or ResultSignature in (\"7002138\", \"700213\")\n| summarize Failures = count(),\n            LastSeen = max(TimeGenerated),\n            Codes = make_set(ResultType, 5),\n            Descriptions = make_set(ResultDescription, 5)\n          by AppId, ServicePrincipalName\n| sort by LastSeen desc\n```"
    },
    {
      "heading": "How do I fix AADSTS7002138?",
      "text": "**For developers and pipeline owners:**\n1. Copy the subject from the error or from the run log (`Federated token details`, `subject claim`).\n2. Either update the credential's subject to that exact string, or change the workflow so the token carries the credential's casing. Microsoft's notice: *\"replace the current `issuer`, `subject`, or `audience` value in the FIC with the `issuer`, `subject`, or `audience` value that was contained in the error message.\"*\n3. For a GitHub environment, renaming it in the workflow (for example `Production` to `production`) is the fix users report and Microsoft suggests for App Service.\n\n**For admins:**\n1. Use the query above to find every app still failing, and fix the credentials in one go.\n2. Microsoft's overview now states the rule plainly: the values *\"must case-sensitively match\"*. Copy values from tokens or logs, never type them by hand."
    }
  ],
  "microsoftWording": {
    "text": "Error: AADSTS7002138: No matching federated identity record found for presented assertion subject 'repo:&lt;org&gt;/&lt;repo&gt;:ref:refs/heads/main'. The subject matches with case-insensitive comparison, but not with case-sensitive comparison.",
    "source": "Quoted on the page from the lab or from user reports; the code is not in Microsoft's error code reference",
    "sourceUrl": null
  },
  "securityReading": {
    "category": {
      "id": "app-config",
      "label": "App configuration"
    },
    "kind": {
      "id": "config",
      "label": "Configuration error"
    },
    "attackSignal": {
      "level": "low",
      "label": "Low: usually configuration or user error"
    },
    "mitre": [],
    "tables": [],
    "isItAnAttack": "No. Entra found a credential that would have matched before the 2024 change. The fix is the casing.\n\n| Pattern | Likely meaning |\n|---|---|\n| A GitHub workflow uses `environment: Production` and the error shows `:environment:Production` | The credential says `production`, or the other way round. On the Q&A thread, the top answer fixed it by renaming the environment to lowercase. Microsoft's notice gives the same advice for Azure App Service users. |\n| The org or repo name has capitals | GitHub sends the casing it holds. The README: uppercase characters in the org, repo, branch or environment name must match the `subject claim` in the run log. |\n| Deployments broke without anyone changing the workflow | The staged rollout above reached your app. |\n| It still fails after \"fixing\" the case | Users report puzzling cases where the subject looks identical (Azure/login issue 573). Copy the subject from the log rather than retyping it. |",
    "conditionalAccess": null
  },
  "kql": [
    {
      "title": null,
      "leadIn": "Microsoft doesn't document which sign-in table 7002138 lands in. Our reading: app registration failures land in `AADServicePrincipalSignInLogs`; a user-assigned managed identity may log in the managed identity sign-in log instead. Check:",
      "query": "union withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7002138\" or ResultSignature == \"7002138\"\n| summarize Rows = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceTable"
    },
    {
      "title": null,
      "leadIn": "To catch every app hit by the case change, list both codes together. If `ResultDescription` holds the returned message (our assumption; check a row), it shows the subject with the casing the token used:",
      "query": "AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType in (\"7002138\", \"700213\") or ResultSignature in (\"7002138\", \"700213\")\n| summarize Failures = count(),\n            LastSeen = max(TimeGenerated),\n            Codes = make_set(ResultType, 5),\n            Descriptions = make_set(ResultDescription, 5)\n          by AppId, ServicePrincipalName\n| sort by LastSeen desc"
    }
  ],
  "kqlSectionText": "Microsoft doesn't document which sign-in table 7002138 lands in. Our reading: app registration failures land in `AADServicePrincipalSignInLogs`; a user-assigned managed identity may log in the managed identity sign-in log instead. Check:\n\n```kusto\nunion withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7002138\" or ResultSignature == \"7002138\"\n| summarize Rows = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceTable\n```\n\nTo catch every app hit by the case change, list both codes together. If `ResultDescription` holds the returned message (our assumption; check a row), it shows the subject with the casing the token used:\n\n```kusto\nAADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType in (\"7002138\", \"700213\") or ResultSignature in (\"7002138\", \"700213\")\n| summarize Failures = count(),\n            LastSeen = max(TimeGenerated),\n            Codes = make_set(ResultType, 5),\n            Descriptions = make_set(ResultDescription, 5)\n          by AppId, ServicePrincipalName\n| sort by LastSeen desc\n```",
  "fix": {
    "short": "Pipeline owner: copy the subject from the error or the run log (`subject claim`) and set the federated credential's subject to that exact string, same case. Or change the workflow to match the credential, for example rename the GitHub environment from `Production` to `production`.",
    "steps": "**For developers and pipeline owners:**\n1. Copy the subject from the error or from the run log (`Federated token details`, `subject claim`).\n2. Either update the credential's subject to that exact string, or change the workflow so the token carries the credential's casing. Microsoft's notice: *\"replace the current `issuer`, `subject`, or `audience` value in the FIC with the `issuer`, `subject`, or `audience` value that was contained in the error message.\"*\n3. For a GitHub environment, renaming it in the workflow (for example `Production` to `production`) is the fix users report and Microsoft suggests for App Service.\n\n**For admins:**\n1. Use the query above to find every app still failing, and fix the credentials in one go.\n2. Microsoft's overview now states the rule plainly: the values *\"must case-sensitively match\"*. Copy values from tokens or logs, never type them by hand."
  },
  "labReproduced": {
    "date": "2026-10-30",
    "method": "Client-credentials token request with a federated identity credential, against a lab tenant",
    "scenario": "Federated credential: subject differs only by case",
    "message": "AADSTS7002138: No matching federated identity record found for presented assertion subject '<subject>'. The subject matches with case-insensitive comparison, but not with case-sensitive comparison.",
    "logCaptured": null,
    "kqlTested": null
  },
  "labSectionText": "On 30 October 2026 an automated lab run set this up in my own tenant: one app registration presents its access token as a client assertion, and a second app carries the federated identity credential that is supposed to accept it. With the credential's subject set to the **same value in different capitals**, Entra returned `AADSTS7002138` rather than 700213:\n\n> AADSTS7002138: No matching federated identity record found for presented assertion subject '<subject>'. The subject matches with case-insensitive comparison, but not with case-sensitive comparison.\n\nThat confirms the split in practice: a subject that is wrong gives [700213](https://brambrinkmeier.com/entra/aadsts/700213/), and a subject that is right apart from capitals gives this code. If you see 7002138, the value is correct and only the case is off, which is usually an environment name such as `Production` against `production`.\n\nThe sign-in log row isn't captured yet; see [how pages are checked](https://brambrinkmeier.com/methodology/).",
  "labRuns": [
    {
      "date": "2026-10-30",
      "run": "round 5",
      "method": "token-endpoint requests against a lab tenant, using lab-created test apps",
      "issue": "https://github.com/GrantZero604/Brambrinkmeier.com/issues/69",
      "scenario": "Federated credential: subject differs only by case",
      "expected": "7002138 / 700213",
      "got": "7002138",
      "matchedExpectation": true,
      "message": "AADSTS7002138: No matching federated identity record found for presented assertion subject '{guid}'. The subject matches with case"
    },
    {
      "date": "2026-10-30",
      "run": "round 6",
      "method": "token-endpoint requests against a lab tenant, using lab-created test apps",
      "issue": "https://github.com/GrantZero604/Brambrinkmeier.com/issues/70",
      "scenario": "Federated credential: subject differs only by case",
      "expected": "7002138 / 700213",
      "got": "7002138",
      "matchedExpectation": true,
      "message": "AADSTS7002138: No matching federated identity record found for presented assertion subject '{guid}'. The subject matches with case"
    },
    {
      "date": "2026-10-30",
      "run": "round 7",
      "method": "token-endpoint requests against a lab tenant",
      "issue": "https://github.com/GrantZero604/Brambrinkmeier.com/issues/71",
      "scenario": "Federated credential: subject differs only by case",
      "expected": "7002138 / 700213",
      "got": "7002138",
      "matchedExpectation": true,
      "message": "AADSTS7002138: No matching federated identity record found for presented assertion subject '{guid}'. The subject matches with case"
    },
    {
      "date": "2026-10-31",
      "run": "round 8",
      "method": "token-endpoint and device-code requests against a lab tenant",
      "issue": "https://github.com/GrantZero604/Brambrinkmeier.com/issues/72",
      "scenario": "Federated credential: subject differs only by case",
      "expected": "7002138 / 700213",
      "got": "7002138",
      "matchedExpectation": true,
      "message": "AADSTS7002138: No matching federated identity record found for presented assertion subject '{guid}'. The subject matches with case"
    },
    {
      "date": "2026-10-31",
      "run": "round 9",
      "method": "token-endpoint and device-code requests against a lab tenant",
      "issue": "https://github.com/GrantZero604/Brambrinkmeier.com/issues/73",
      "scenario": "Federated credential: subject differs only by case",
      "expected": "7002138 / 700213",
      "got": "7002138",
      "matchedExpectation": true,
      "message": "AADSTS7002138: No matching federated identity record found for presented assertion subject '{guid}'. The subject matches with case"
    }
  ],
  "verification": "lab-reproduced",
  "related": [
    "700213",
    "70021",
    "700211",
    "700212",
    "70025",
    "7002121"
  ],
  "coveredBy": [],
  "sources": [
    {
      "title": "Microsoft Entra authentication and authorization error codes",
      "url": "https://learn.microsoft.com/lb-lu/entra/identity-platform/reference-error-codes"
    },
    {
      "title": "Azure/login GitHub Action README",
      "url": "https://github.com/Azure/login#readme"
    },
    {
      "title": "Federated identity credentials and case-sensitive matching (Microsoft Entra breaking changes, August 2024)",
      "url": "https://learn.microsoft.com/en-us/entra/identity-platform/reference-breaking-changes"
    },
    {
      "title": "Github quit deploying to azure (Microsoft Q&A)",
      "url": "https://learn.microsoft.com/en-us/answers/questions/2181284/github-quit-deploying-to-azure"
    },
    {
      "title": "Federated credentials does not work on main branch (Azure/login issue 573)",
      "url": "https://github.com/Azure/login/issues/573"
    },
    {
      "title": "Workload identity federation",
      "url": "https://learn.microsoft.com/entra/workload-id/workload-identity-federation"
    },
    {
      "title": "AADServicePrincipalSignInLogs table reference (Azure Monitor)",
      "url": "https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/aadserviceprincipalsigninlogs"
    }
  ],
  "published": "2026-10-30",
  "lastUpdated": "2026-10-30",
  "lastVerified": null,
  "license": "CC BY 4.0",
  "licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
  "licenseNote": "CC BY 4.0 covers the author's own text and classification fields. Quoted Microsoft error wording belongs to Microsoft, is quoted with its source and can change.",
  "attribution": "Bram Brinkmeier, \"AADSTS7002138: Federated credential subject differs in case (fix)\", https://brambrinkmeier.com/entra/aadsts/7002138/ (CC BY 4.0)",
  "microsoftErrorLookup": "https://login.microsoftonline.com/error?code=7002138"
}
