Conversation
auth_google_access_token exchanges a Google OAuth access token at /api/v2/auth/google-access-token, for clients that can mint access tokens without a browser but can't get ID tokens. auth_id_token does the same with an ID token at /api/v2/auth/oidc-callback-token. Both take a function that returns a token rather than the token itself, and call it again whenever the session token expires, so long-running clients outlive the first token. The three auth methods share _start_session, which sends the exchange without retries. A 401 from an auth endpoint used to trigger refresh_auth, which called the auth method again: once a session existed, a revoked API key recursed until RecursionError. Session tokens go through _set_session_token, which updates the headers of the existing requests session instead of replacing the session. Subclasses that send requests through another transport override it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds client methods for
POST /api/v2/auth/google-access-tokenfrom yeti-platform/yeti#1403 and for the existing ID token endpoint. It also fixes a refresh loop on rejected credentials, which the new methods would otherwise inherit.What changed
auth_google_access_token(token_provider)exchanges a Google OAuth access token for a session token. It's for clients that can mint access tokens without a browser but can't get ID tokens. The server must run withauth.module = oidcandauth.google_access_token_client_idsset. Otherwise the endpoint answers 404, which surfaces asYetiApiErrorwithstatus_code == 404.auth_id_token(token_provider)does the same with an ID token at/api/v2/auth/oidc-callback-token. That endpoint had no client method.refresh_auth()calls the auth method again with no arguments, and the method calls the provider for a fresh token. Session tokens expire after 30 minutes by default and Google access tokens after about an hour, so a long-running client can't keep reusing the first token. There's no new dependency: with google-auth, the provider is a few lines that refresh the credentials and returncredentials.token.refresh_auth()→auth_api_key()→ 401 →refresh_auth()…. Once a session existed, a revoked API key recursed untilRecursionError, sending a request at each level. The three auth methods now share_start_session, which sends the exchange withretries=0. A rejected credential raisesYetiAuthErrorafter one attempt._set_session_token. Auth methods now hand the session token to this method. It updates the headers of the existingrequests.Session, whereauth_api_keyused to replace the session with a new one. That keeps the session's settings (TLS verification, adapters, hooks). It also gives subclasses that send requests through another transport a single method to override._auth_function_mapis typed asdict[str, Callable[[], None]], matching howrefresh_authcalls its values.Verification
Unit and type checks, run the way CI does after
poetry install --no-root:poetry run python -m unittest tests/api.py: 47 passed (8 new). Onmain'syeti/api.py,test_auth_api_key_revokederrors withRecursionError.poetry run pyrefly check: 0 errorstests/e2e.pyagainst a local Yeti built frommainplus yeti-platform/yeti#1403, using API key auth: 14 passed.I also ran the client against two local Yeti servers built from that branch, one with the exchange enabled and one without. It used real Google access tokens for my account, fetched through the provider and never printed:
The request lists come from a response hook on the client's session, and
mintedis a running count of provider calls. To expire a session, the check replaced the session token with an invalid one. Between steps, it disabled the user, then the API key, directly in the server's database. The output shows one renewal attempt per expired session, and no retry loop when the server rejects the credential. A successfulauth_id_tokenisn't covered: a Google ID token for the test server's client needs a browser flow. The check only confirms that the endpoint receives the token and that a rejection raisesYetiAuthError.Release
No version bump: 2.4.0, from #28, isn't released yet, and this ships with it.
auth_google_access_tokenneeds a server with yeti-platform/yeti#1403. Against older servers it raisesYetiApiError(404).