# AADSTS9002327: SPA token redeemed without a browser Origin (fix)

Canonical: https://brambrinkmeier.com/entra/aadsts/9002327/
By Bram Brinkmeier. JSON: https://brambrinkmeier.com/api/aadsts/9002327.json

**Short answer:** AADSTS9002327 means a token request used an authorization code or refresh token issued to a single-page app, but the request had no Origin header, so it didn't come from a browser. Microsoft's error reference doesn't list it. A Q&A answerer links it to redemption from server-side code. Low attack value. Redeem in the browser, or register a Web platform.

**Fix:** Developer: if the browser redeems tokens, let MSAL.js in the browser make the token call. If your server redeems the code or refreshes tokens, register a Web redirect URI and authenticate the server as a confidential client. Don't fake the `Origin` header in a backend. User: report the app name.

| Field | Value |
|---|---|
| Code | AADSTS9002327 |
| Category | App configuration |
| Type | Configuration error |
| Attack signal | Low: usually configuration or user error |
| In Microsoft's error reference | No (checked 2026-10-30) |
| Verification | documentation |
| Last updated | 2026-10-30 |

## What does AADSTS9002327 mean?

Microsoft's [error code reference](https://learn.microsoft.com/entra/identity-platform/reference-error-codes) doesn't list AADSTS9002327 (checked 30 October 2026).

The wording below comes from user reports. A user on Microsoft Q&A posted this token endpoint response (`400 Bad Request`, `invalid_request`):

> AADSTS9002327: Tokens issued for the 'Single-Page Application' client-type may only be redeemed via cross-origin requests.

The app was registered with the **Single-page application** platform and used the authorization code flow with PKCE. A Microsoft moderator answered that the error is thrown *"due to your token requests missing the Origin header"*, and gave two fixes: add the header, or change the redirect URI platform to **Web** or **Native/Desktop**. Another answerer, not marked as Microsoft staff, wrote: *"Usually, you get the AADSTS9002327 error when trying to exchange a refresh token from server-side code."*. The thread doesn't confirm which applied.

Microsoft documents the rule, without the code number, in its authorization code flow reference:

> Applications can't use a `spa` redirect URI with non-SPA flows, for example, native applications or client credential flows. To ensure security and best practices, the Microsoft identity platform returns an error if you attempt to use a `spa` redirect URI without an `Origin` header.

Our reading: 9002327 is that error. A code or refresh token issued through a `spa` redirect URI can only be redeemed by a request that carries an `Origin` header, which is what a browser sends. It is the mirror of [9002326](https://brambrinkmeier.com/entra/aadsts/9002326/), where a request with an `Origin` header hits an app that isn't an SPA.

## Is it an attack?

No. It is a mismatch between how the app is registered and where it redeems tokens.

| Pattern | Likely meaning |
|---|---|
| A developer testing the token call in Postman or curl | No `Origin` header is sent. The SPA registration rejects it. Likely, but unconfirmed. |
| An app that renders on the server (SSR, Blazor Server, MVC) registered as SPA | One Q&A answerer suggests this: the code is redeemed by server code, not the browser. |
| A backend that takes the SPA's refresh token and refreshes it itself | One Q&A answerer calls this the usual cause. The refresh token stays bound to the browser. |
| A sudden spike after a deployment | Probably token redemption moved from the browser to a backend or proxy (unconfirmed). |

Our reading: the check is a defence. A code or refresh token issued to a browser app can't simply be redeemed from a script without the `Origin` header. Anyone can set that header in a script, though, so it is not a strong barrier. Don't treat it as one.

## How do I find it in my logs (KQL)?

Microsoft doesn't document which sign-in table 9002327 is logged in, or whether it is logged at all. Check where it lands in your workspace:

```kusto
union withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs
| where TimeGenerated > ago(30d)
| where ResultType == "9002327"
| summarize Rows = count() by SourceTable
```

If it does land in a user sign-in table, find the apps and the clients behind it. A server or tool user agent instead of a browser points at server-side redemption:

```kusto
union SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(30d)
| where ResultType == "9002327"
| summarize Rows = count(),
            Users = dcount(UserPrincipalName),
            UserAgents = make_set(UserAgent, 10),
            IPs = make_set(IPAddress, 10)
          by AppDisplayName, AppId
| sort by Rows desc
```

## How do I fix AADSTS9002327?

**For the user:** you can't fix this yourself. Report the app name to whoever runs it.

**For developers:**
1. Decide where tokens should be redeemed. If the browser does it, use MSAL.js in the browser and let it make the token call. The browser sends the `Origin` header.
2. If your server redeems the code or refreshes tokens, the app isn't an SPA. Register a **Web** redirect URI and authenticate the server as a confidential client. That is one of the two fixes the Microsoft moderator gave.
3. The moderator's other fix was to add the `Origin` header. Our reading: fine for a test in Postman or curl. Don't ship a backend that fakes a browser header to get around the SPA rules.
4. Don't mix flows on one redirect URI. Microsoft: *"Applications can't use a `spa` redirect URI with non-SPA flows."*

**For admins:**
1. Look at the app registration's **Authentication** page. Check which platform the failing redirect URI is under: **Single-page application**, **Web**, or **Mobile and desktop applications**.
2. If the app's backend does the redemption, move that redirect URI to **Web**, with the developer's agreement. Moving it changes how the app must authenticate.

## Evidence

Not in Microsoft's error reference and not reproduced in the lab; built from lab results, other Microsoft pages and user reports, which the page names.

Lab-run rows naming this code (5; full list at https://brambrinkmeier.com/lab-runs.json):

| Date | Scenario | Expected | Got | Message (first line) |
|---|---|---|---|---|
| 2026-10-30 | SPA-registered client redeems without an Origin header | 9002327 | 65001 | AADSTS65001: The user or administrator has not consented to use the application with ID '{app-id}' named 'lab-spa-41136574530'. Send |
| 2026-10-30 | SPA-registered client redeems without an Origin header | 9002327 / 65001 | 65001 | AADSTS65001: The user or administrator has not consented to use the application with ID '{app-id}' named 'lab-spa-41139925607'. Send |
| 2026-10-30 | SPA-registered client redeems without an Origin header | 9002327 / 65001 | 65001 | AADSTS65001: The user or administrator has not consented to use the application with ID '{app-id}' named 'lab-spa-41143330001'. Send |
| 2026-10-31 | SPA-registered client redeems without an Origin header | 9002327 / 65001 | 65001 | AADSTS65001: The user or administrator has not consented to use the application with ID '{app-id}' named 'lab-spa-41146039117'. Send |
| 2026-10-31 | SPA-registered client redeems without an Origin header | 9002327 / 65001 | 65001 | AADSTS65001: The user or administrator has not consented to use the application with ID '{app-id}' named 'lab-spa-41150019626'. Send |

## Sources

1. [Microsoft Entra authentication and authorization error codes](https://learn.microsoft.com/entra/identity-platform/reference-error-codes)
2. [Microsoft Q&A: AADSTS9002327: Tokens issued for the 'Single-Page Application' client-type may only be redeemed via cross-origin requests (1601797)](https://learn.microsoft.com/en-us/answers/questions/1601797/aadsts9002327-tokens-issued-for-the-single-page-ap)
3. [Microsoft identity platform and OAuth 2.0 authorization code flow](https://learn.microsoft.com/entra/identity-platform/v2-oauth2-auth-code-flow)
4. [SigninLogs table reference (Azure Monitor)](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs)

## Related codes

[AADSTS9002326](https://brambrinkmeier.com/entra/aadsts/9002326/), [AADSTS700054](https://brambrinkmeier.com/entra/aadsts/700054/), [AADSTS9002313](https://brambrinkmeier.com/entra/aadsts/9002313/), [AADSTS7000218](https://brambrinkmeier.com/entra/aadsts/7000218/), [AADSTS700081](https://brambrinkmeier.com/entra/aadsts/700081/)

## License and citation

CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). 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.

Cite as: Bram Brinkmeier, "AADSTS9002327: SPA token redeemed without a browser Origin (fix)", https://brambrinkmeier.com/entra/aadsts/9002327/ (CC BY 4.0), last updated 2026-10-30.
