Skip to content

Commit 5f0ecdb

Browse files
Ambient Code Botclaude
andcommitted
fix: replace authlib with requests to eliminate AuthlibDeprecationWarning
Remove the authlib dependency which triggers a deprecation warning from its internal authlib.jose module on every import. Replace the OAuth2Session usage with a lightweight _OAuth2Client class that uses requests.Session directly for OAuth2 flows. Fixes #627 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 72e0ed8 commit 5f0ecdb

3 files changed

Lines changed: 76 additions & 18 deletions

File tree

python/packages/jumpstarter-cli-common/jumpstarter_cli_common/oidc.py

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,95 @@
11
import json
22
import os
3+
import secrets
34
import ssl
45
import time
56
from dataclasses import dataclass
67
from functools import wraps
78
from typing import ClassVar
9+
from urllib.parse import parse_qs, urlencode, urlparse
810

911
import aiohttp
1012
import certifi
1113
import click
14+
import requests
1215
from aiohttp import web
1316
from anyio import create_memory_object_stream
1417
from anyio.to_thread import run_sync
15-
from authlib.integrations.requests_client import OAuth2Session
1618
from joserfc.jws import extract_compact
1719
from yarl import URL
1820

1921
from jumpstarter.config.env import JMP_OIDC_CALLBACK_PORT
2022

2123

24+
class _OAuth2Client:
25+
"""Lightweight OAuth2 client using requests.Session.
26+
27+
Replaces authlib.integrations.requests_client.OAuth2Session to avoid
28+
the AuthlibDeprecationWarning triggered by authlib's internal
29+
authlib.jose imports (see https://github.com/jumpstarter-dev/jumpstarter/issues/627).
30+
"""
31+
32+
def __init__(self, client_id: str, scope: list[str], redirect_uri: str | None = None):
33+
self.client_id = client_id
34+
self.scope = scope
35+
self.redirect_uri = redirect_uri
36+
self._session = requests.Session()
37+
38+
@property
39+
def verify(self):
40+
return self._session.verify
41+
42+
@verify.setter
43+
def verify(self, value):
44+
self._session.verify = value
45+
46+
def create_authorization_url(self, url: str, **kwargs) -> tuple[str, str]:
47+
"""Build an authorization URL with a generated state parameter."""
48+
state = secrets.token_urlsafe(32)
49+
params = {
50+
"response_type": "code",
51+
"client_id": self.client_id,
52+
"scope": " ".join(self.scope),
53+
"state": state,
54+
}
55+
if self.redirect_uri:
56+
params["redirect_uri"] = self.redirect_uri
57+
params.update(kwargs)
58+
separator = "&" if "?" in url else "?"
59+
return f"{url}{separator}{urlencode(params)}", state
60+
61+
def fetch_token(self, url: str, **kwargs) -> dict:
62+
"""Exchange credentials for an OAuth2 token via HTTP POST."""
63+
data = {"client_id": self.client_id}
64+
65+
# Handle authorization_response: extract the code from the callback URL
66+
authorization_response = kwargs.pop("authorization_response", None)
67+
if authorization_response:
68+
parsed = urlparse(authorization_response)
69+
qs = parse_qs(parsed.query)
70+
code = qs.get("code", [None])[0]
71+
if code:
72+
data["code"] = code
73+
if self.redirect_uri:
74+
data["redirect_uri"] = self.redirect_uri
75+
data.setdefault("grant_type", "authorization_code")
76+
77+
# Merge remaining kwargs into the POST body
78+
data.update(kwargs)
79+
80+
# Ensure scope is a space-separated string
81+
if "scope" not in data:
82+
data["scope"] = " ".join(self.scope)
83+
84+
response = self._session.post(
85+
url,
86+
data=data,
87+
headers={"Accept": "application/json"},
88+
)
89+
response.raise_for_status()
90+
return response.json()
91+
92+
2293
def _get_ssl_context() -> ssl.SSLContext:
2394
"""Create an SSL context that respects SSL_CERT_FILE environment variable."""
2495
ssl_ctx = ssl.create_default_context()
@@ -77,7 +148,7 @@ def _scopes(self) -> list[str]:
77148
return list(self.scope)
78149

79150
def client(self, **kwargs):
80-
session = OAuth2Session(client_id=self.client_id, scope=self._scopes(), **kwargs)
151+
session = _OAuth2Client(client_id=self.client_id, scope=self._scopes(), **kwargs)
81152
session.verify = False if self.insecure_tls else (os.environ.get("SSL_CERT_FILE") or certifi.where())
82153
return session
83154

python/packages/jumpstarter-cli-common/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies = [
1010
"jumpstarter",
1111
"pydantic>=2.8.2",
1212
"click>=8.1.7.2",
13-
"authlib>=1.4.1",
13+
"requests>=2.32.0",
1414
"truststore>=0.10.1",
1515
"joserfc>=1.0.3",
1616
"yarl>=1.18.3",

python/uv.lock

Lines changed: 2 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)