|
4 | 4 | from collections.abc import Sequence |
5 | 5 | from datetime import datetime |
6 | 6 | from datetime import timedelta |
7 | | -from functools import partial |
8 | 7 | from typing import Any |
9 | 8 | from typing import Optional |
10 | 9 |
|
|
16 | 15 | from IPython.display import display |
17 | 16 | from jupyterhub.services.auth import HubAuth |
18 | 17 |
|
| 18 | +# Refresh window was modified in: https://github.com/googleapis/google-auth-library-python/commit/c6af1d692b43833baca978948376739547cf685a |
| 19 | +# The change was directed towards high latency environments, and should not apply to us. |
| 20 | +# Since we can't force a refresh, the threshold is lowered to keep us from waiting ~4 minutes for a new token. |
| 21 | +# A permanent fix would be to supply credentials with a refresh endpoint |
| 22 | +# that allways returns a token that is valid for more than 3m 45s. |
| 23 | +google.auth._helpers.REFRESH_THRESHOLD = timedelta(seconds=20) |
| 24 | + |
19 | 25 |
|
20 | 26 | class AuthClient: |
21 | 27 | """Client for retrieving authentication information.""" |
@@ -107,24 +113,22 @@ def fetch_google_credentials() -> Credentials: |
107 | 113 | """ |
108 | 114 | if AuthClient.is_ready(): |
109 | 115 | try: |
| 116 | + |
| 117 | + def _refresh_handler( |
| 118 | + request: google.auth.transport.Request, scopes: Sequence[str] |
| 119 | + ) -> tuple[str, datetime]: |
| 120 | + # We manually override the refresh_handler method with our custom logic for fetching tokens. |
| 121 | + # Previously, we directly overrode the `refresh` method. However, this |
| 122 | + # approach led to deadlock issues in gcsfs/credentials.py's maybe_refresh method. |
| 123 | + return AuthClient.fetch_google_token() |
| 124 | + |
110 | 125 | token, expiry = AuthClient.fetch_google_token() |
111 | 126 | credentials = Credentials( |
112 | 127 | token=token, |
113 | 128 | expiry=expiry, |
114 | 129 | token_uri="https://oauth2.googleapis.com/token", |
| 130 | + refresh_handler=_refresh_handler, |
115 | 131 | ) |
116 | | - |
117 | | - def _refresh(self: Credentials, request: Any) -> None: |
118 | | - token, expiry = AuthClient.fetch_google_token(request) |
119 | | - self.token = token |
120 | | - self.expiry = expiry |
121 | | - |
122 | | - # We need to manually override the refresh method. |
123 | | - # This is because the "Credentials" class' built-in refresh method |
124 | | - # requires that the token be *at least valid for 3 minutes and 45 seconds*. |
125 | | - # We cannot make this guarantee in JupyterHub due to the implementation |
126 | | - # of our TokenExchange endpoint. |
127 | | - credentials.refresh = partial(_refresh, credentials) # type: ignore[method-assign] |
128 | 132 | except AuthError as err: |
129 | 133 | err._print_warning() |
130 | 134 |
|
|
0 commit comments