Skip to content

feat: auto-fetch token for client_credentials grant in OAuth2Session/OAuth2Client#895

Open
liudonggalaxy wants to merge 1 commit into
authlib:mainfrom
liudonggalaxy:Dongliu/oauth2_session_auto_fetch_token_for_client_credentials
Open

feat: auto-fetch token for client_credentials grant in OAuth2Session/OAuth2Client#895
liudonggalaxy wants to merge 1 commit into
authlib:mainfrom
liudonggalaxy:Dongliu/oauth2_session_auto_fetch_token_for_client_credentials

Conversation

@liudonggalaxy

@liudonggalaxy liudonggalaxy commented May 18, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

This is a feature implementation.

When using OAuth2Session (requests) or OAuth2Client (httpx) with the client_credentials grant type, the caller must explicitly call fetch_token() before making any resource request, even though all the required metadata (token_endpoint, grant_type, client_id, client_secret) is already configured on the session. This is inconsistent with AssertionSession, which transparently auto-fetches tokens via ensure_active_token().

Before:

from authlib.integrations.requests_client import OAuth2Session

sess = OAuth2Session(
    client_id="my-client",
    client_secret="my-secret",
    token_endpoint="https://auth.example.com/token",
    grant_type="client_credentials",
)

# Must manually fetch before any request — raises MissingTokenError otherwise
sess.fetch_token("https://auth.example.com/token")
resp = sess.get("https://api.example.com/resource")

After:

from authlib.integrations.requests_client import OAuth2Session

sess = OAuth2Session(
    client_id="my-client",
    client_secret="my-secret",
    token_endpoint="https://auth.example.com/token",
    grant_type="client_credentials",
)

# Token is fetched automatically on first request
resp = sess.get("https://api.example.com/resource")

Solution: In request() (and stream() for httpx), when self.token is None and the configured grant_type is "client_credentials", call self.fetch_token() automatically. Since fetch_token() already reads token_endpoint and grant_type from self.metadata when not explicitly provided, the call is simply self.fetch_token() with no arguments needed.

For non-client_credentials grant types, the existing MissingTokenError / OAuthError behavior is preserved unchanged.

Fully backward compatible — sessions that already call fetch_token() explicitly continue to work identically.

Checklist

  • The commits follow the conventional commits specification.
  • You ran the linters with prek.
  • You wrote unit test to demonstrate the bug you are fixing, or to stress the feature you are bringing.
  • You reached 100% of code coverage on the code you edited, without abusive use of pragma: no cover
  • If this PR is about a new feature, or a behavior change, you have updated the documentation accordingly.

  • You consent that the copyright of your pull request source code belongs to Authlib's author.

@liudonggalaxy liudonggalaxy marked this pull request as draft May 18, 2026 21:18
@liudonggalaxy liudonggalaxy changed the title feat: auto-fetch token for client_credentials grant in OAuth2Session feat: auto-fetch token for client_credentials grant in OAuth2Session/OAuth2Client May 18, 2026
@liudonggalaxy liudonggalaxy force-pushed the Dongliu/oauth2_session_auto_fetch_token_for_client_credentials branch 16 times, most recently from 5d72302 to a588623 Compare May 19, 2026 00:50
When OAuth2Session/OAuth2Client is configured with
grant_type='client_credentials' and token_endpoint, automatically
fetch an access token on the first request instead of raising
MissingTokenError/OAuthError.

The logic lives in a single _ensure_token() method on the base
OAuth2Client class. For async clients, a thin override awaits the
coroutine returned by the parent.

Co-authored-by: Copilot <[email protected]>
@liudonggalaxy liudonggalaxy force-pushed the Dongliu/oauth2_session_auto_fetch_token_for_client_credentials branch from a588623 to 5171bc6 Compare May 19, 2026 00:54
@liudonggalaxy liudonggalaxy marked this pull request as ready for review May 19, 2026 01:37
Comment on lines -137 to -138
if not self.token:
raise MissingTokenError()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the if not self.token: raise MissingTokenError() was removed from requests_client/oauth2_session.py's request() method:

The token check and auto-fetch is now handled automatically by the auth layer. When request() sets auth = self.token_auth, it creates an OAuth2Auth instance. During the request, OAuth2Auth.__call__() invokes self.client.ensure_active_token(self.token), which:

  1. If token is None and grant_type="client_credentials" → calls self.fetch_token() automatically
  2. If token is None and no auto-fetch is possible → raises MissingTokenError
  3. If token exists but is expired → refreshes it

So the explicit check in request() was redundant — OAuth2Auth already triggers ensure_active_token() which handles all cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant