{
  "schemaVersion": "1.0",
  "code": "90015",
  "name": "QueryStringTooLong",
  "title": "AADSTS90015 fix: sign-in request URL is too long",
  "url": "https://brambrinkmeier.com/entra/aadsts/90015/",
  "alternates": {
    "markdown": "https://brambrinkmeier.com/entra/aadsts/90015.md",
    "json": "https://brambrinkmeier.com/api/aadsts/90015.json",
    "html": "https://brambrinkmeier.com/entra/aadsts/90015/"
  },
  "description": "AADSTS90015: the sign-in request URL was too long for Entra. Shrink state and return URLs, or wait for the app vendor's fix. KQL included.",
  "summary": "AADSTS90015 means the sign-in request URL Entra received had a query string that was too long. Sign-in requests travel as URL parameters, so a large state value, a long return URL or a chain of identity providers can push it over the limit. Users report it from Jira Cloud for Outlook, Azure Databricks and chained Okta setups. Low attack value.",
  "inMicrosoftReference": true,
  "unlistedChecked": null,
  "meaningText": "Microsoft's description:\n\n> **QueryStringTooLong**: The query string is too long.\n\nThe message users see is *\"AADSTS90015: Requested query string is too long.\"*\n\nSign-in requests to Entra ID are URLs. An OAuth 2.0 or OpenID Connect sign-in is a request to the `/authorize` endpoint with everything in the query string: `client_id`, `redirect_uri`, `scope`, `state` and more. A SAML sign-in works the same way: Microsoft's SAML reference says the app *\"uses an HTTP Redirect binding to pass an `AuthnRequest`\"* to Entra ID. If that URL gets too long, Entra ID rejects the request with 90015.\n\nMicrosoft doesn't publish the limit. Atlassian's support article says Microsoft restricts query parameters *\"to a maximum of 2048 characters\"*; we haven't found that number in Microsoft's documentation.\n\nWhat makes a request long, in our reading:\n- **The `state` parameter.** Microsoft says it *\"can be a string of any content that you wish\"* and *\"can also encode information about the user's state in the app\"*. Apps that pack a lot into it make every sign-in URL longer.\n- **Long return or deep-link URLs**, carried inside `redirect_uri`, `state` or a SAML `RelayState`, and URL-encoded on top.\n- **Chained identity providers.** Each hop can wrap the previous request in its own. A user on the Okta forum reports the error only with Okta → Okta → Entra ID; single-hop setups worked.",
  "sections": [
    {
      "heading": "What does AADSTS90015 mean?",
      "text": "Microsoft's description:\n\n> **QueryStringTooLong**: The query string is too long.\n\nThe message users see is *\"AADSTS90015: Requested query string is too long.\"*\n\nSign-in requests to Entra ID are URLs. An OAuth 2.0 or OpenID Connect sign-in is a request to the `/authorize` endpoint with everything in the query string: `client_id`, `redirect_uri`, `scope`, `state` and more. A SAML sign-in works the same way: Microsoft's SAML reference says the app *\"uses an HTTP Redirect binding to pass an `AuthnRequest`\"* to Entra ID. If that URL gets too long, Entra ID rejects the request with 90015.\n\nMicrosoft doesn't publish the limit. Atlassian's support article says Microsoft restricts query parameters *\"to a maximum of 2048 characters\"*; we haven't found that number in Microsoft's documentation.\n\nWhat makes a request long, in our reading:\n- **The `state` parameter.** Microsoft says it *\"can be a string of any content that you wish\"* and *\"can also encode information about the user's state in the app\"*. Apps that pack a lot into it make every sign-in URL longer.\n- **Long return or deep-link URLs**, carried inside `redirect_uri`, `state` or a SAML `RelayState`, and URL-encoded on top.\n- **Chained identity providers.** Each hop can wrap the previous request in its own. A user on the Okta forum reports the error only with Okta → Okta → Entra ID; single-hop setups worked."
    },
    {
      "heading": "Is it an attack?",
      "text": "No. It is a request Entra ID couldn't accept, not a failed credential check, and no token is issued. Users report it in these settings:\n\n| Pattern | Likely meaning |\n|---|---|\n| Many users of one SaaS app at once, starting on the same day | A change on the app vendor's side. In March 2026 Azure Databricks users in several tenants reported it; a Microsoft Q&A moderator called it a service-side issue, and Databricks fixed it on its side. |\n| One add-on or app, mostly when the user isn't signed in to it yet | The app's own sign-in flow builds a long URL. Atlassian documents this for Jira Cloud for Outlook. |\n| SAML through more than one identity provider | Chained redirects. Reported with Okta in front of Entra ID. |\n| One user, intermittently | Our interpretation: a bookmark or deep link with a long return URL. Try the app's normal start page. |"
    },
    {
      "heading": "How do I find it in my logs (KQL)?",
      "text": "Microsoft doesn't document whether a 90015 is written to the sign-in logs. The request is rejected early, and we don't know whether a row is created. Check all three tables:\n\n```kusto\nunion withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(7d)\n| where ResultType == \"90015\"\n| summarize Rows = count(), Users = dcount(UserPrincipalName) by SourceTable\n```\n\nIf rows exist, find the app, the protocol and the browser. `AuthenticationProtocol` tells SAML (`saml20`) from OAuth (`oAuth2`):\n\n```kusto\nunion SigninLogs, AADNonInteractiveUserSignInLogs\n| where TimeGenerated > ago(7d)\n| where ResultType == \"90015\"\n| summarize Rows = count(), Users = dcount(UserPrincipalName),\n            FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated),\n            UserAgents = make_set(UserAgent, 5)\n          by AppDisplayName, AppId, AuthenticationProtocol\n| sort by Users desc\n```\n\nSudden spread across users of one app, the vendor-side pattern. Five users in an hour is a starting point:\n\n```kusto\nSigninLogs\n| where TimeGenerated > ago(1d)\n| where ResultType == \"90015\"\n| summarize Users = dcount(UserPrincipalName) by AppDisplayName, bin(TimeGenerated, 1h)\n| where Users >= 5\n| sort by TimeGenerated desc\n```\n\nIf the first query returns nothing while users do see the error, the request probably never produced a sign-in row. Then the browser is your only evidence: ask the user for the Request ID, Correlation ID and timestamp from the error page."
    },
    {
      "heading": "How do I fix AADSTS90015?",
      "text": "**For the user:**\n1. Open the app from its normal start address, not from an old bookmark or a link deep inside the app.\n2. Clear cookies for the site, or use a private window, and keep only one account signed in. These are the steps suggested to Databricks users while the vendor fix was pending.\n3. Jira Cloud for Outlook: Atlassian's fix is to sign in to `id.atlassian.com` with Microsoft first, then connect the add-on from Outlook on the web, and then go back to the desktop app.\n4. If it still fails, report it with the Request ID, Correlation ID and timestamp from the error page.\n\n**For developers:**\n1. Keep `state` short. Microsoft: *\"do not put URLs or other sensitive data directly in the state parameter. Instead, use a key or identifier that corresponds to data stored in browser storage\"*.\n2. Don't carry long deep-link URLs through the sign-in. Store the target and pass a short key.\n3. Request only the scopes you need at sign-in. Every scope adds to the URL.\n4. For chained identity providers, cut a hop if you can. Our reading is that each hop adds its own wrapped request.\n\n**For admins:**\n1. Many users of one app at the same time points to the vendor. Check their status page or support before changing anything in your tenant.\n2. For a home-built app, send the second query's result to the developer with the steps above."
    }
  ],
  "microsoftWording": {
    "text": "**QueryStringTooLong**: The query string is too long.",
    "source": "Microsoft's error code reference, as quoted on the page",
    "sourceUrl": "https://learn.microsoft.com/en-us/entra/identity-platform/reference-error-codes"
  },
  "securityReading": {
    "category": {
      "id": "request",
      "label": "Graph request shape"
    },
    "kind": {
      "id": "failure",
      "label": "Failure"
    },
    "attackSignal": {
      "level": "low",
      "label": "Low: usually configuration or user error"
    },
    "mitre": [],
    "tables": [],
    "isItAnAttack": "No. It is a request Entra ID couldn't accept, not a failed credential check, and no token is issued. Users report it in these settings:\n\n| Pattern | Likely meaning |\n|---|---|\n| Many users of one SaaS app at once, starting on the same day | A change on the app vendor's side. In March 2026 Azure Databricks users in several tenants reported it; a Microsoft Q&A moderator called it a service-side issue, and Databricks fixed it on its side. |\n| One add-on or app, mostly when the user isn't signed in to it yet | The app's own sign-in flow builds a long URL. Atlassian documents this for Jira Cloud for Outlook. |\n| SAML through more than one identity provider | Chained redirects. Reported with Okta in front of Entra ID. |\n| One user, intermittently | Our interpretation: a bookmark or deep link with a long return URL. Try the app's normal start page. |",
    "conditionalAccess": null
  },
  "kql": [
    {
      "title": null,
      "leadIn": "Microsoft doesn't document whether a 90015 is written to the sign-in logs. The request is rejected early, and we don't know whether a row is created. Check all three tables:",
      "query": "union withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(7d)\n| where ResultType == \"90015\"\n| summarize Rows = count(), Users = dcount(UserPrincipalName) by SourceTable"
    },
    {
      "title": null,
      "leadIn": "If rows exist, find the app, the protocol and the browser. `AuthenticationProtocol` tells SAML (`saml20`) from OAuth (`oAuth2`):",
      "query": "union SigninLogs, AADNonInteractiveUserSignInLogs\n| where TimeGenerated > ago(7d)\n| where ResultType == \"90015\"\n| summarize Rows = count(), Users = dcount(UserPrincipalName),\n            FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated),\n            UserAgents = make_set(UserAgent, 5)\n          by AppDisplayName, AppId, AuthenticationProtocol\n| sort by Users desc"
    },
    {
      "title": null,
      "leadIn": "Sudden spread across users of one app, the vendor-side pattern. Five users in an hour is a starting point:",
      "query": "SigninLogs\n| where TimeGenerated > ago(1d)\n| where ResultType == \"90015\"\n| summarize Users = dcount(UserPrincipalName) by AppDisplayName, bin(TimeGenerated, 1h)\n| where Users >= 5\n| sort by TimeGenerated desc"
    }
  ],
  "kqlSectionText": "Microsoft doesn't document whether a 90015 is written to the sign-in logs. The request is rejected early, and we don't know whether a row is created. Check all three tables:\n\n```kusto\nunion withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs\n| where TimeGenerated > ago(7d)\n| where ResultType == \"90015\"\n| summarize Rows = count(), Users = dcount(UserPrincipalName) by SourceTable\n```\n\nIf rows exist, find the app, the protocol and the browser. `AuthenticationProtocol` tells SAML (`saml20`) from OAuth (`oAuth2`):\n\n```kusto\nunion SigninLogs, AADNonInteractiveUserSignInLogs\n| where TimeGenerated > ago(7d)\n| where ResultType == \"90015\"\n| summarize Rows = count(), Users = dcount(UserPrincipalName),\n            FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated),\n            UserAgents = make_set(UserAgent, 5)\n          by AppDisplayName, AppId, AuthenticationProtocol\n| sort by Users desc\n```\n\nSudden spread across users of one app, the vendor-side pattern. Five users in an hour is a starting point:\n\n```kusto\nSigninLogs\n| where TimeGenerated > ago(1d)\n| where ResultType == \"90015\"\n| summarize Users = dcount(UserPrincipalName) by AppDisplayName, bin(TimeGenerated, 1h)\n| where Users >= 5\n| sort by TimeGenerated desc\n```\n\nIf the first query returns nothing while users do see the error, the request probably never produced a sign-in row. Then the browser is your only evidence: ask the user for the Request ID, Correlation ID and timestamp from the error page.",
  "fix": {
    "short": "User: open the app from its normal start URL, not a bookmark or deep link, clear cookies or use a private window, and try again. Developer: keep the request small. Put a short key in `state`, not a URL or app data, and shorten return URLs. Many users at once: it is likely on the app's side.",
    "steps": "**For the user:**\n1. Open the app from its normal start address, not from an old bookmark or a link deep inside the app.\n2. Clear cookies for the site, or use a private window, and keep only one account signed in. These are the steps suggested to Databricks users while the vendor fix was pending.\n3. Jira Cloud for Outlook: Atlassian's fix is to sign in to `id.atlassian.com` with Microsoft first, then connect the add-on from Outlook on the web, and then go back to the desktop app.\n4. If it still fails, report it with the Request ID, Correlation ID and timestamp from the error page.\n\n**For developers:**\n1. Keep `state` short. Microsoft: *\"do not put URLs or other sensitive data directly in the state parameter. Instead, use a key or identifier that corresponds to data stored in browser storage\"*.\n2. Don't carry long deep-link URLs through the sign-in. Store the target and pass a short key.\n3. Request only the scopes you need at sign-in. Every scope adds to the URL.\n4. For chained identity providers, cut a hop if you can. Our reading is that each hop adds its own wrapped request.\n\n**For admins:**\n1. Many users of one app at the same time points to the vendor. Check their status page or support before changing anything in your tenant.\n2. For a home-built app, send the second query's result to the developer with the steps above."
  },
  "labReproduced": null,
  "labSectionText": null,
  "labRuns": [],
  "verification": "documentation",
  "related": [
    "9002313",
    "900144"
  ],
  "coveredBy": [],
  "sources": [
    {
      "title": "Microsoft Entra authentication and authorization error codes",
      "url": "https://learn.microsoft.com/entra/identity-platform/reference-error-codes"
    },
    {
      "title": "Microsoft identity platform and OAuth 2.0 authorization code flow",
      "url": "https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow"
    },
    {
      "title": "Single sign-on SAML protocol",
      "url": "https://learn.microsoft.com/entra/identity-platform/single-sign-on-saml-protocol"
    },
    {
      "title": "SigninLogs table reference (Azure Monitor)",
      "url": "https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs"
    },
    {
      "title": "Jira Cloud for Outlook: AADSTS90015: Requested query string is too long (Atlassian)",
      "url": "https://support.atlassian.com/jira/kb/jira-cloud-for-outlook-aadsts90015-requested-query-string-is-too-long/"
    },
    {
      "title": "AADSTS90015 Requested query string is too long (Microsoft Q&A)",
      "url": "https://learn.microsoft.com/en-us/answers/questions/5827320/aadsts90015-requested-query-string-is-too-long"
    },
    {
      "title": "AADSTS90015: Requested query string is too long (Okta developer forum)",
      "url": "https://devforum.okta.com/t/aadsts90015-requested-query-string-is-too-long/15905/5"
    }
  ],
  "published": "2026-11-01",
  "lastUpdated": "2026-11-01",
  "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, \"AADSTS90015 fix: sign-in request URL is too long\", https://brambrinkmeier.com/entra/aadsts/90015/ (CC BY 4.0)",
  "microsoftErrorLookup": "https://login.microsoftonline.com/error?code=90015"
}
