fastapi-azure-auth: [BUG/Question] Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type.
Describe 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
}
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 19 (11 by maintainers)
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.
Hi,
The application created for OpenAPI seems to be configured for
web
and notSpa
. See this section:The application itself should looke something like this:
and the OpenAPI application registration should look something like this: