googleapis / google-auth-library-python

Google Auth Python Library
https://googleapis.dev/python/google-auth/latest/
Apache License 2.0
771 stars 304 forks source link

Unable to use async application default credentials with `AuthorizedSession` #1417

Closed and3rson closed 9 months ago

and3rson commented 9 months ago

Environment details

Steps to reproduce

import asyncio
from google.auth._default_async import default_async
from google.auth.transport import _aiohttp_requests

async def main():
    creds, project = default_async()
    await creds.refresh(_aiohttp_requests.Request())
    print('Credentials:', creds)
    async with _aiohttp_requests.AuthorizedSession(creds) as authed_session:
        response = await authed_session.request('POST', 'https://example.org'))
        print(response.json())

asyncio.run(main())

Actual result:

Credentials: <google.oauth2._credentials_async.Credentials object at 0x7fc2e3ea9f10>
...
  File "/usr/local/lib/python3.11/site-packages/google/auth/transport/_aiohttp_requests.py", line 333, in request
    await self.credentials.before_request(
TypeError: object NoneType can't be used in 'await' expression

This seems to happen since google.oauth2._credentials_async.Credentials does not define asynchronous version of before_request, while google.auth._credentials_async.Credentials does this.

and3rson commented 9 months ago

I found a temporary solution by monkey-patching before_request in obtained credentials with implementation from _credentials_async.Credentials.before_request:

from google.auth._credentials_async import Credentials

async def main():
    creds, project = default_async()
    await creds.refresh(_aiohttp_requests.Request())
    creds.before_request = partial(Credentials.before_request, creds)
    # ...
clundin25 commented 9 months ago

Thank you for pointing this out! It seems the pattern in the sync code is that oauth2.credentials.Credentials inherits from auth.credentials.Credentials, but for the async code it inherits from the sync equivalent.

I think the correct solution is to add before_request to the oauth2 async Credentials class. An alternative is to revisit the existing inheritance. We can do that at a later time, when we have the resources to "release" the async code.