[BUG/Question] Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type.
See original GitHub issueDescribe the bug
Auth error
Error: Bad Request,
error: invalid_request,
description: AADSTS9002326: Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type.
To Reproduce
This is the minimal FastAPI app:
from pydantic import AnyHttpUrl, BaseSettings, Field
from fastapi.middleware.cors import CORSMiddleware
from typing import Union
class Settings(BaseSettings):
SECRET_KEY: str = Field('my super secret key', env='SECRET_KEY')
BACKEND_CORS_ORIGINS: list[Union[str, AnyHttpUrl]] = ['http://localhost:8000']
OPENAPI_CLIENT_ID: str = Field(default='', env='OPENAPI_CLIENT_ID')
APP_CLIENT_ID: str = Field(default='', env='APP_CLIENT_ID')
TENANT_ID: str = Field(default='', env='TENANT_ID')
class Config:
env_file = '.env'
env_file_encoding = 'utf-8'
case_sensitive = True
from fastapi import FastAPI
settings = Settings()
app = FastAPI()
settings = Settings()
if settings.BACKEND_CORS_ORIGINS:
app.add_middleware(
CORSMiddleware,
allow_origins=[str(origin) for origin in settings.BACKEND_CORS_ORIGINS],
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)
app = FastAPI(
swagger_ui_oauth2_redirect_url='/oauth2-redirect',
swagger_ui_init_oauth={
'usePkceWithAuthorizationCodeGrant': True,
'clientId': settings.OPENAPI_CLIENT_ID,
})
from fastapi_azure_auth import SingleTenantAzureAuthorizationCodeBearer
azure_scheme = SingleTenantAzureAuthorizationCodeBearer(
app_client_id=settings.APP_CLIENT_ID,
tenant_id=settings.TENANT_ID,
scopes={
#"User.ReadBasic.All": 'read'
'https://graph.microsoft.com/.default': 'default'
#AADSTS70011
#f'api://{settings.APP_CLIENT_ID}/user_impersonation': 'user_impersonation',
})
@app.on_event('startup')
async def load_config() -> None:
""" Load OpenID config on startup. """
await azure_scheme.openid_config.load_config()
from fastapi import Security, responses
@app.get("/", dependencies=[Security(azure_scheme, scopes=["default"])])
def read_root():
"""
Redirects to /docs
"""
return "It works."
Please, set the following envars:
export TENANT_ID=<your-tenant_id>
export OPENAPI_CLIENT_ID=<your-client_id>
export APP_CLIENT_ID="https://login.microsoftonline.com/$TENANT_ID"
export SECRET_KEY=<your-secret>
Steps to reproduce the behavior:
- Go to http://localhost:8000/docs
- Click in ‘Autorize’
- Leave client_secret blank, and select scopes
- Click in ‘Autorize’, the page will return the error
Configuration
I believe this bug is related to my Azure AD set up, so may provide the Manifest from AD.
Sensitive information is hidden and the <CENSORED>
is put in place.
{
"id": "<CENSORED>",
"acceptMappedClaims": null,
"accessTokenAcceptedVersion": 2,
"addIns": [],
"allowPublicClient": false,
"appId": "<CENSORED>",
"appRoles": [],
"oauth2AllowUrlPathMatching": false,
"createdDateTime": "2022-01-11T19:43:15Z",
"description": null,
"certification": null,
"disabledByMicrosoftStatus": null,
"groupMembershipClaims": null,
"identifierUris": [],
"informationalUrls": {
"termsOfService": null,
"support": null,
"privacy": null,
"marketing": null
},
"keyCredentials": [],
"knownClientApplications": [],
"logoUrl": null,
"logoutUrl": "https://localhost:8000/oauth2-redirect",
"name": "backoffice",
"notes": null,
"oauth2AllowIdTokenImplicitFlow": true,
"oauth2AllowImplicitFlow": true,
"oauth2Permissions": [],
"oauth2RequirePostResponse": false,
"optionalClaims": null,
"orgRestrictions": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [
{
"customKeyIdentifier": null,
"endDate": "2022-04-21T17:02:20.006Z",
"keyId": "<CENSORED>",
"startDate": "2022-01-21T17:02:20.006Z",
"value": null,
"createdOn": "2022-01-21T17:02:31.8956842Z",
"hint": ".F7",
"displayName": "API-Test"
}
],
"preAuthorizedApplications": [],
"publisherDomain": "<CENSORED>",
"replyUrlsWithType": [
{
"url": "http://localhost:8000/",
"type": "Web"
},
{
"url": "http://localhost:8000/oauth2-redirect",
"type": "Web"
},
],
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
},
{
"id": "14dad69e-099b-42c9-810b-d002981feec1",
"type": "Scope"
}
]
}
],
"samlMetadataUrl": null,
"serviceManagementReference": null,
"signInUrl": null,
"signInAudience": "AzureADMyOrg",
"tags": [],
"tokenEncryptionKeyId": null
}
Issue Analytics
- State:
- Created 2 years ago
- Comments:17 (10 by maintainers)
Top Results From Across the Web
Cross-origin token redemption is permitted only for the 'Single ...
Cross-origin token redemption is permitted only for the 'Single-Page Application ' In angular . While genrating token for using graph api in ...
Read more >AADSTS9002326: Cross-origin token redemption is permitted ...
When I run the code block below, I get 400 bad request errors. Proxy code '/payment': { target: 'https://apitest.domain ...
Read more >Do I need to enable Cors? Tokens issued for the 'Single-Page ...
Tokens issued for the 'Single-Page Application' client-type may only be redeemed via cross-origin requests.
Read more >Add `Origin` header to OAuth 2.0 flow - Help - Postman
Error: AADSTS9002327: Tokens issued for the 'Single-Page Application' client-type may only be redeemed via cross-origin requests.
Read more >Making cross-origin, browser-side API requests
Zendesk only implements CORS for API requests authenticated with OAuth ... If the end user grants your app access, the token is sent...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Hi,
That’s not a silly question! You would use something called Client Credentials flow. Basically just create a secret for your app reg and do something like this:
or if you use httpx:
If I don’t remember wrong, you have to use the
.default
scope. So if your backend app reg client ID isabcd
then your scope should beapi://abcd/.default
.Hi!
There’s two ways, either using the request object as seen here, or adding a dependency in the input of your function, as seen here.