Wie implementiere ich OAuth2 in meine requests.Session Klasse?
Verfasst: Montag 4. März 2024, 22:00
Hi,
ich stehe vor einem Problem das ich anscheinend nicht selbst gelöst bekomme. Ich habe bereits eine ganze Weile recherchiert, aber auch das hat mich nicht voran gebracht. Ich hoffe inständig dass ihr mir hier vielleicht weiterhelfen könnt, bzw. mich in die richtige Richtung weisen könnt.
Ich habe eine BaseClient Klasse die von requests.Session, requests_cache.session.CacheMixin und requests_ratelimiter.LimiterMixin erbt. Die Klasse dient als Grundgerüst für Implementationen diverser API clients. Zwei Clients die einen API key nutzen habe ich bereits testweise aufgebaut und das funktioniert wunderbar.
Nun möchte ich einen weiteren API client implementieren, der nun allerdings OAuth2 nutzen muss. Dafür möchte ich requests-oauthlib mit dem Backend Application Flow verwenden, da der API Anbieter (DigiKey) mir CLIENT_ID und CLIENT_SECRET zur Authentifizierung zur Verfügung stellt, siehe hier. Das Beispiel aus der Dokumentation funktioniert eigenständig auch wunderbar:
Nun möchte ich diese Funktionalität in meine DigiKey Klasse implementieren. Diese erbt vom BaseClient und zusätzlich von requests_oauthlib.OAuth2Session. (Später werden weitere OAuth2 clients hinzu kommen, von daher wird das dann irgendwann wohl in eine BaseClientOAuth o.Ä. Klasse wandern...) Ich habe das folgendermaßen versucht:
Das resultiert jedoch in folgendem Fehler:
Warum fehlt hier anscheinend ein Parameter?
Egal wie sehr ich mich auch bemühe und in den Klassen Definitionen etc. rum suche, ich komme einfach nicht drauf was hier nicht passt.
Ich bin für jede Hilfe dankbar!
ich stehe vor einem Problem das ich anscheinend nicht selbst gelöst bekomme. Ich habe bereits eine ganze Weile recherchiert, aber auch das hat mich nicht voran gebracht. Ich hoffe inständig dass ihr mir hier vielleicht weiterhelfen könnt, bzw. mich in die richtige Richtung weisen könnt.
Ich habe eine BaseClient Klasse die von requests.Session, requests_cache.session.CacheMixin und requests_ratelimiter.LimiterMixin erbt. Die Klasse dient als Grundgerüst für Implementationen diverser API clients. Zwei Clients die einen API key nutzen habe ich bereits testweise aufgebaut und das funktioniert wunderbar.
Code: Alles auswählen
from requests import Session
from requests_cache import CacheMixin
from requests_ratelimiter import LimiterMixin
from pyrate_limiter import SQLiteBucket
from urllib.parse import urljoin
class BaseClient(CacheMixin, LimiterMixin, Session):
def __init__(self, *, cache_name="cache", cache_lifetime=-1, **kwargs):
super().__init__(
# requests_cache
cache_name=cache_name,
expire_after=cache_lifetime,
allowable_methods=['GET', 'POST'],
# requests_ratelimiter
bucket_class=SQLiteBucket,
max_delay=10, # in seconds
**kwargs
)
def request(self, method, endpoint, *args, **kwargs):
return super().request(method, urljoin(self.base_url, endpoint), *args, **kwargs)
Code: Alles auswählen
import os
from dotenv import load_dotenv
from rich import print
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
load_dotenv()
client_id = os.getenv("DIGIKEY_API_CLIENT_ID")
client_secret = os.getenv("DIGIKEY_API_CLIENT_SECRET")
client = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(
token_url='https://sandbox-api.digikey.com/v1/oauth2/token',
client_id=client_id,
client_secret=client_secret,
include_client_id=True
)
print(token)
Code: Alles auswählen
from pyrate_limiter import Duration, RequestRate, Limiter
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import BackendApplicationClient
from urllib.parse import urljoin
from .utils import BaseClient
class DigiKey(BaseClient, OAuth2Session):
limit_per_minute = RequestRate(120, Duration.MINUTE)
limit_per_day = RequestRate(1000, Duration.DAY)
limiter = Limiter(limit_per_minute, limit_per_day)
base_url = "https://sandbox-api.digikey.com"
def __init__(self, *, client_id, client_secret, **kwargs):
self.xclient_id = client_id
self.xclient_secret = client_secret
self.xclient = BackendApplicationClient(client_id=self.xclient_id)
super().__init__(cache_name="temp/digikey", limiter=self.limiter, client=self.xclient, **kwargs)
self.token = self.fetch_token(
token_url=urljoin(self.base_url, "/v1/oauth2/token"),
client_id=self.xclient_id,
client_secret=self.xclient_secret,
include_client_id=True
)
print(self.token)
Code: Alles auswählen
Traceback (most recent call last):
File "/home/12vich2o/projekte/api-client/oauth-test.py", line 27, in <module>
digikey = DigiKey(client_id=client_id, client_secret=client_secret)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/12vich2o/projekte/api-client/api_client/digikey.py", line 21, in __init__
self.token = self.fetch_token(
^^^^^^^^^^^^^^^^^
File "/home/12vich2o/projekte/api-client/.venv/lib/python3.11/site-packages/requests_oauthlib/oauth2_session.py", line 251, in fetch_token
raise ValueError(
ValueError: Please supply either code or authorization_response parameters.
Egal wie sehr ich mich auch bemühe und in den Klassen Definitionen etc. rum suche, ich komme einfach nicht drauf was hier nicht passt.

Ich bin für jede Hilfe dankbar!
