{
  "schemaVersion": "1.0",
  "code": "7000110",
  "name": null,
  "title": "AADSTS7000110: Code or refresh token used by a different app (fix)",
  "url": "https://brambrinkmeier.com/entra/aadsts/7000110/",
  "alternates": {
    "markdown": "https://brambrinkmeier.com/entra/aadsts/7000110.md",
    "json": "https://brambrinkmeier.com/api/aadsts/7000110.json",
    "html": "https://brambrinkmeier.com/entra/aadsts/7000110/"
  },
  "description": "AADSTS7000110: a code or refresh token was redeemed with the wrong client ID. Not in Microsoft's error list. Cause, fix and KQL.",
  "summary": "AADSTS7000110 means an authorization code or refresh token was redeemed with a client ID other than the one it was issued to. Microsoft's error reference doesn't list it, but a Microsoft troubleshooting article does. Usually a config mix-up between two app registrations. Low attack value, but check unfamiliar IPs. Use the same client ID.",
  "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 AADSTS7000110 (checked 30 October 2026).\n\nMicrosoft documents it in a troubleshooting article. The message:\n\n> Request is ambiguous, multiple application identifiers found. The client ID used to obtain the grant (e.g. refresh token or authorization code) might not match the client ID passed in this request or client credential.\n\nMicrosoft's cause: the application tried to\n\n> - Redeem an OAuth2 authorization code to get an access token or a refresh token that has the wrong application ID (`client_id` parameter).\n> - Use a refresh token that was initially issued to the application ID of a different caller.\n\nAn authorization code or refresh token belongs to the app that requested it. If the token request names another app, Entra sees two app IDs and refuses. The \"client credential\" part of the message suggests a third variant. Our reading: a confidential client whose secret or certificate belongs to a different app registration than the `client_id`. Microsoft's article doesn't list that case.",
  "sections": [
    {
      "heading": "What does AADSTS7000110 mean?",
      "text": "Microsoft's [error code reference](https://learn.microsoft.com/entra/identity-platform/reference-error-codes) doesn't list AADSTS7000110 (checked 30 October 2026).\n\nMicrosoft documents it in a troubleshooting article. The message:\n\n> Request is ambiguous, multiple application identifiers found. The client ID used to obtain the grant (e.g. refresh token or authorization code) might not match the client ID passed in this request or client credential.\n\nMicrosoft's cause: the application tried to\n\n> - Redeem an OAuth2 authorization code to get an access token or a refresh token that has the wrong application ID (`client_id` parameter).\n> - Use a refresh token that was initially issued to the application ID of a different caller.\n\nAn authorization code or refresh token belongs to the app that requested it. If the token request names another app, Entra sees two app IDs and refuses. The \"client credential\" part of the message suggests a third variant. Our reading: a confidential client whose secret or certificate belongs to a different app registration than the `client_id`. Microsoft's article doesn't list that case."
    },
    {
      "heading": "Is it an attack?",
      "text": "Usually not. It is a config mix-up.\n\n| Pattern | Likely meaning |\n|---|---|\n| Fails right after a code is returned to the app | The authorize request and the token request use different client IDs. Common when an app has separate dev and prod registrations. |\n| A refresh token stored by one app is reused by another | Probably two apps share a token cache or a database table (unconfirmed). |\n| Fails after an app registration was replaced | Stored refresh tokens still belong to the old app ID. Users have to sign in again. |\n| Refresh tokens for your users presented from IPs and user agents your apps don't use | Our interpretation: someone may be replaying a token captured from one app under another client ID. Check the IPs before dismissing it. |"
    },
    {
      "heading": "How do I find it in my logs (KQL)?",
      "text": "Microsoft doesn't document which sign-in table 7000110 is logged in. Check where it lands in your workspace:\n\n```kusto\nunion withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7000110\"\n| summarize Rows = count() by SourceTable\n```\n\nWhich apps, and from where. Many users on one app is a config bug. One user from an unfamiliar IP is worth a closer look:\n\n```kusto\nunion SigninLogs, AADNonInteractiveUserSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7000110\"\n| summarize Rows = count(),\n            Users = dcount(UserPrincipalName),\n            IPs = make_set(IPAddress, 10),\n            UserAgents = make_set(UserAgent, 5),\n            FirstSeen = min(TimeGenerated)\n          by AppDisplayName, AppId\n| sort by Users asc\n```\n\nOur reading: the `AppId` in the row is probably the client ID that was sent in the token request, not the one the token was issued to. That isn't documented. Non-interactive rows are aggregated, so counts are not request counts."
    },
    {
      "heading": "How do I fix AADSTS7000110?",
      "text": "**For the user:** sign out of the app and sign in again. If it keeps happening, report it to the app's owner.\n\n**For developers:**\n1. Microsoft's fix: *\"Use an OAuth2 authorization code or a refresh token that's from the same application ID (`client_id` parameter).\"*\n2. Check that the authorize request and the token request read the client ID from the same setting. Look for a dev client ID in one place and a prod one in another.\n3. Keep refresh tokens per app. Don't share a token cache between two app registrations.\n4. For a confidential client, check that the secret or certificate belongs to the same app registration as the `client_id`. This step comes from the message's \"client credential\" wording, which Microsoft doesn't explain.\n5. After replacing an app registration, clear the stored refresh tokens and send users through sign-in. Microsoft's refresh token page says apps should handle revoked tokens *\"by redirecting the user to an interactive sign-in prompt\"*.\n\n**For admins:**\n1. Find the app in the second query and give the developer its `AppId`, plus the app ID they expected.\n2. If the rows come from IPs or user agents that none of your apps use, treat it like a suspicious token use. Look at the same user's successful non-interactive sign-ins from those IPs."
    }
  ],
  "microsoftWording": {
    "text": "Request is ambiguous, multiple application identifiers found. The client ID used to obtain the grant (e.g. refresh token or authorization code) might not match the client ID passed in this request or client credential.",
    "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": "token",
      "label": "Tokens and sessions"
    },
    "kind": {
      "id": "config",
      "label": "Configuration error"
    },
    "attackSignal": {
      "level": "low",
      "label": "Low: usually configuration or user error"
    },
    "mitre": [],
    "tables": [],
    "isItAnAttack": "Usually not. It is a config mix-up.\n\n| Pattern | Likely meaning |\n|---|---|\n| Fails right after a code is returned to the app | The authorize request and the token request use different client IDs. Common when an app has separate dev and prod registrations. |\n| A refresh token stored by one app is reused by another | Probably two apps share a token cache or a database table (unconfirmed). |\n| Fails after an app registration was replaced | Stored refresh tokens still belong to the old app ID. Users have to sign in again. |\n| Refresh tokens for your users presented from IPs and user agents your apps don't use | Our interpretation: someone may be replaying a token captured from one app under another client ID. Check the IPs before dismissing it. |",
    "conditionalAccess": null
  },
  "kql": [
    {
      "title": null,
      "leadIn": "Microsoft doesn't document which sign-in table 7000110 is logged in. Check where it lands in your workspace:",
      "query": "union withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7000110\"\n| summarize Rows = count() by SourceTable"
    },
    {
      "title": null,
      "leadIn": "Which apps, and from where. Many users on one app is a config bug. One user from an unfamiliar IP is worth a closer look:",
      "query": "union SigninLogs, AADNonInteractiveUserSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7000110\"\n| summarize Rows = count(),\n            Users = dcount(UserPrincipalName),\n            IPs = make_set(IPAddress, 10),\n            UserAgents = make_set(UserAgent, 5),\n            FirstSeen = min(TimeGenerated)\n          by AppDisplayName, AppId\n| sort by Users asc"
    }
  ],
  "kqlSectionText": "Microsoft doesn't document which sign-in table 7000110 is logged in. Check where it lands in your workspace:\n\n```kusto\nunion withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7000110\"\n| summarize Rows = count() by SourceTable\n```\n\nWhich apps, and from where. Many users on one app is a config bug. One user from an unfamiliar IP is worth a closer look:\n\n```kusto\nunion SigninLogs, AADNonInteractiveUserSignInLogs\n| where TimeGenerated > ago(30d)\n| where ResultType == \"7000110\"\n| summarize Rows = count(),\n            Users = dcount(UserPrincipalName),\n            IPs = make_set(IPAddress, 10),\n            UserAgents = make_set(UserAgent, 5),\n            FirstSeen = min(TimeGenerated)\n          by AppDisplayName, AppId\n| sort by Users asc\n```\n\nOur reading: the `AppId` in the row is probably the client ID that was sent in the token request, not the one the token was issued to. That isn't documented. Non-interactive rows are aggregated, so counts are not request counts.",
  "fix": {
    "short": "Developer: redeem the authorization code or refresh token with the same `client_id` that requested it. Read the client ID from one setting for both requests, keep refresh tokens per app, and check the secret or certificate belongs to that same app. User: sign out and sign in again.",
    "steps": "**For the user:** sign out of the app and sign in again. If it keeps happening, report it to the app's owner.\n\n**For developers:**\n1. Microsoft's fix: *\"Use an OAuth2 authorization code or a refresh token that's from the same application ID (`client_id` parameter).\"*\n2. Check that the authorize request and the token request read the client ID from the same setting. Look for a dev client ID in one place and a prod one in another.\n3. Keep refresh tokens per app. Don't share a token cache between two app registrations.\n4. For a confidential client, check that the secret or certificate belongs to the same app registration as the `client_id`. This step comes from the message's \"client credential\" wording, which Microsoft doesn't explain.\n5. After replacing an app registration, clear the stored refresh tokens and send users through sign-in. Microsoft's refresh token page says apps should handle revoked tokens *\"by redirecting the user to an interactive sign-in prompt\"*.\n\n**For admins:**\n1. Find the app in the second query and give the developer its `AppId`, plus the app ID they expected.\n2. If the rows come from IPs or user agents that none of your apps use, treat it like a suspicious token use. Look at the same user's successful non-interactive sign-ins from those IPs."
  },
  "labReproduced": null,
  "labSectionText": null,
  "labRuns": [],
  "verification": "documentation",
  "related": [
    "700016",
    "70008",
    "700082",
    "7000215"
  ],
  "coveredBy": [],
  "sources": [
    {
      "title": "Microsoft Entra authentication and authorization error codes",
      "url": "https://learn.microsoft.com/entra/identity-platform/reference-error-codes"
    },
    {
      "title": "Error AADSTS7000110: Request is ambiguous, multiple application identifiers found",
      "url": "https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/app-integration/error-code-aadsts7000110-request-is-ambiguous"
    },
    {
      "title": "Refresh tokens in the Microsoft identity platform",
      "url": "https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens"
    },
    {
      "title": "SigninLogs table reference (Azure Monitor)",
      "url": "https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs"
    }
  ],
  "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, \"AADSTS7000110: Code or refresh token used by a different app (fix)\", https://brambrinkmeier.com/entra/aadsts/7000110/ (CC BY 4.0)",
  "microsoftErrorLookup": "https://login.microsoftonline.com/error?code=7000110"
}
