Triggering an OAuth flow from a Python FastAPI backend, returns an access_token malformed

I am creating a backend with Python and FastAPI to authenticate users using the OAuth flow. Unfortunately there are no implementations with FastAPI that I could find so I adapted this Flask implementation https://github.com/auth0-samples/auth0-python-web-app/tree/master/01-Login

Using OAuth from authlib.integrations.starlette_client I’m able to trigger the OAuth flow and a user can navigate to the single singon page and login. However, the access_token returned from the authentication flow is not working.

The token seems to be malformed with 2 dots ( … ) in what I think should be the payload (?) and when I try to verify this token with our other backend it returns an error with Audience Invalid.

This is the code I used:

oauth_client = OAuth()

oauth_client.register(
name=“auth0”,
client_id=settings.auth0_client_id,
client_secret=settings.auth0_client_secret,
audience=settings.auth0_audience,
authorize_url=f"https://{settings.auth0_domain}/authorize",
token_url=f"https://{settings.auth0_domain}/oauth/token",
server_metadata_url=f"https://{settings.auth0_domain}/.well-known/openid-configuration",
client_kwargs={
“scope”: “openid profile email”,
},
)

The audience parameter there doesn’t seem to do anything BTW

Then from a login route I direct the user to a callback:

@router.get(“/login”)
async def login(request: Request):
try:
return await oauth_client.auth0.authorize_redirect(
request=request,
redirect_uri=settings.auth0_callback_url,
state=request.query_params.get(“state”),
)
except Exception as e:
logger.error(
f"Could not redirect to Auth0 login page. Error: {str(e)}", exc_info=True
)
raise CouldNotRedirectToOAuthException(str(e))

@router.api_route(path=“/callback”, methods=[“GET”, “POST”])
async def callback(request: Request):
try:
code = request.query_params.get(“code”)
state = request.query_params.get(“state”)
if code:
# Exchange the authorization code for an access token using Auth0’s token endpoint
token = await oauth_client.auth0.authorize_access_token(request)

       # the access_token returned by authorize_access_token is not well formed.

        verified_token = await verify_token_authenticity(token)
        return RedirectResponse(settings.slack_install_url)
except Exception as e:
    logger.error(
        f"Could not verify user authentication. Error: {str(e)}", exc_info=True
    )
    raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(e))

I would appreciate any help in this topic

Hey @leonardo1 welcome to the community!

What does the the token payload look like when you paste it into jwt.io (please redact any sensitive info)? Additionally, what does the payload look like for the authorize request when inspecting the network tab? Again, please redact any info you deem necessary.

Hey @tyf, thank you!

This is what I see in jwt.io

this is what is see for the payload:

I do see the payload is missing a lot of parameters compared to the one you have shared.

Thanks for sharing!

The access token does indeed seem to be missing some parameters - audience being critical to receiving a jwt as opposed to an opaque token. There’s definitely an issue with the way the authorize request is being configured/constructed.

If you want to quickly test your API, you can always navigate to the API in your dashboard → Test tab and grab an access token for an authorized client.

Well, that is a great question @tyf

This is my first time using Auth0 to authenticate users. I have inherited the stack and I don’t understand the configuration.

This are our Applications:

This is our API:

Our React (Frontend APP) uses the Staging oauth app client_id and client_secret to do loginWithRedirect to the users and after that it does getAccessTokenSilently.

I wanted to replicate process from the React App and direct users to login and get the token from that Stating application’s client_id and client_secret.

When I test the token from the API that token works but it has no user attached, which is probably fine.

What I don’t understand is why we have 2 different apps with different credentials to manage SSO and API tokens.

Do you have any documentation of how to achieve this process in python correctly?

1 Like

That’s good news at least!

In this case you can ignore the M2M app and focus on the SPA as you will use this to get a user’s access token. We unfortunately don’t have a clear example, but here is what I would do:

  • Here is our Python sample which utilizes Flask. You should be able to get this up and running with your domain and API identifier fairly quickly.

  • Take a look at our React sample app and get it up and running with your SPA application ids. Be sure and add the audience (your API identifier) in the auth_config.json file. When running the app and logging in, have the network tab open so that you can extract the user’s access token - You will see a call to the /token endpoint:

  • Once you have the access token from a test user, check out our docs on how to use the API. This is the quickstart that pairs with our Python sample API/app referenced in bullet 1. This outlines a few curl requests you can make to the Python sample API you have running using the access token you extracted previously.

Hope this helps!

@tyf I have tried what you sent me, and the React code works fine and gives me the token as you mentioned and I can use it in my Backend to authenticate.

One thing I noticed I was missing was to redirect the users after doing SSO to the homepage of my application. After doing that I can see the call that looks like this:

https://******.us.auth0.com/u/login?state=hKFo2SB5QXM0eUc2QjBrcFpZbVhsOFdnZ3VHZk14c2dzdGdEMqFur3VuaXZlcnNhbC1sb2dpbqN0aWTZIE5tRWw1dzhQM041bkQwcWFGcGNlenRtWXN1N2kzajZzo2NpZNkgOEdqUlBHMzNZb0hpQjc0SFNWV0xDOHdLRmt4Yk40dXk

with the payload of the username and password in it.

Now I think the problem here is that I’m using FastAPI to return HTML templates and I don’t have a way to get the bearer token as you mention above in that token call – I guess that is probably getTokenSilently --.

This:

How can I do that call from the Python Backend? Because I don’t have the username and password of the user to make that call from the backend. I probably need some other way of getting that token on behalf of the user.