Package: requests-oauth2client
requests_oauth2clientis an OAuth 2.x client for Python, able to obtain, refresh and revoke tokens from any
OAuth2.x/OIDC compliant Authorization Server. It sits upon and extends the famousrequestsHTTP client module.It can act as anOAuth 2.0/2.1client, to automatically get and renew Access Tokens,
based on theClient Credentials,Authorization Code,Refresh token,Token Exchange,JWT Bearer,Device Authorization,Resource Owner PasswordorCIBAgrants. Additional
grant types are easy to add if needed.It also supportsOpenID Connect 1.0,PKCE,Client Assertions,Token Revocation, andIntrospection,Resource Indicators,JWT-secured Authorization Requests,Pushed Authorization Requests,Authorization Server Issuer Identification, as well as using custom
params to any endpoint, and other important features that are often overlooked in other client libraries.And it also includes awrapperaroundrequests.Sessionthat makes it super easy to use REST-style APIs,
with or without OAuth 2.x.Please note that despite the name, this library has no relationship with Googleoauth2clientlibrary.DocumentationFull module documentation is available athttps://guillp.github.io/requests_oauth2client/Installationrequests_oauth2clientisavailable from PyPi, so installing it is
as easy as:pipinstallrequests_oauth2clientUsageEverything fromrequests_oauth2clientis available from the root module, so you can import it like this:fromrequests_oauth2clientimport*Or you can import individual objects from this package as usual. Note that importing*automatically importsrequests, so no need to import it yourself.Calling APIs with Access TokensIf you already managed to obtain an access token for the API you want to call, you can simply use theBearerAuthAuth
Handler forrequests:importrequestsfromrequests_oauth2clientimportBearerAuthtoken="an_access_token"resp=requests.get("https://my.protected.api/endpoint",auth=BearerAuth(token))This authentication handler will add a properly formattedAuthorization: Bearer <access_token>header in the request,
with your access token according toRFC6750.Using an OAuth2ClientOAuth2Clientoffers several methods that implement the communication to the various endpoints that are standardised by
OAuth 2.0 and its extensions. Those endpoints include the Token Endpoint, the Revocation, Introspection, UserInfo,
BackChannel Authentication and Device Authorization Endpoints.You have to provide the URLs for those endpoints if you intend to use them. Otherwise, only the Token Endpoint is
mandatory to initialize anOAuth2Client.To initialize anOAuth2Client, you only need a Token Endpoint URI from your AS, and the credentials for your
application, which are often aclient_idand aclient_secret, usually also provided by the AS:fromrequests_oauth2clientimportOAuth2Clientoauth2client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",client_id="my_client_id",client_secret="my_client_secret",)The Token Endpoint is the only endpoint that is mandatory to obtain tokens. Credentials are used to authenticate the
client everytime it sends a request to its Authorization Server. Usually, those are a static Client ID and Secret, which
are the direct equivalent of a username and a password, but meant for an application instead of for a human user. The
default authentication method used byOAuth2ClientisClient Secret Post, but other standardised methods such asClient Secret Basic,Client Secret JWTorPrivate Key JWTare supported as well. Seemore about client authentication methods below.Obtaining tokensOAuth2Clienthas dedicated methods to send requests to the Token Endpoint using the different standardised (and/or
custom) grants. Since the Token Endpoint URL and Client Authentication Method to use are already declared for the client
at init time, the only required parameters for those methods are those that will be sent in the request to the Token
Endpoint.Those methods directly return aBearerTokenif the request is successful, or raise an exception if it fails.BearerTokencontains all the data as returned by the Token Endpoint, including the Access Token. It will:keep track of the Access Token expiration date (based on theexpires_inhint as returned by the AS). This date is
accessible with theexpires_atattribute.contain the Refresh Token, if returned by the AS, accessible with therefresh_tokenattribute.contain the ID Token, if returned by the AS, accessible with theìd_tokenattribute (when using the Authorization
Code flow).keep track of other associated metadata as well, also accessible as attributes with the same name:token.custom_attr, or with subscription syntaxtoken["my.custom.attr"].You can create such aBearerTokenyourself if you need:fromrequests_oauth2clientimportBearerTokenbearer_token=BearerToken(access_token="an_access_token",expires_in=60)print(bearer_token)# {'access_token': 'an_access_token',#  'expires_in': 55,#  'token_type': 'Bearer'}print(bearer_token.expires_at)# datetime.datetime(2021, 8, 20, 9, 56, 59, 498793)assertnotbearer_token.is_expired()print(bearer_token.expires_in)# 40Note that theexpires_inindicator here is not static. It keeps track of the token lifetime, in seconds, and is
calculated as the time flies. The actual static expiration date is accessible with theexpires_atproperty. You can
check if a token is expired withbearer_token.is_expired().You can use aBearerTokeninstance anywhere you can use an access_token as string.Using OAuth2Client as a requests Auth HandlerWhile usingOAuth2Clientdirectly is great for testing or debugging OAuth2.x flows, it is not a viable option for
actual applications where tokens must be obtained, used during their lifetime then obtained again or refreshed once they
are expired.requests_oauth2clientcontains severalrequestscompatible Auth Handlers (as subclasses ofrequests.auth.AuthBase), that will
take care of obtaining tokens when required, then will cache those tokens until they are expired, and will obtain new
ones (or refresh them, when possible), once the initial token is expired. Those are best used with arequests.Session,
or anApiClient, which is a wrapper aroundSessionwith a few enhancements as described below.Client Credentials grantTo send a request using the Client Credentials grant, use the aptly named.client_credentials()method, with the parameters to send in the token request as keyword parameters:fromrequests_oauth2clientimportOAuth2Clientoauth2client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",auth=("client_id","client_secret"),)token=oauth2client.client_credentials(scope="myscope")# or, if your AS uses resource indicator:token=oauth2client.client_credentials(scope="myscope",resource="https://myapi.local")# or, if your AS uses 'audience' as parameter to identify the requested API (Auth0 style):token=oauth2client.client_credentials(audience="https://myapi.local")# or, if your AS uses custom parameters:token=oauth2client.client_credentials(scope="myscope",custom_param="custom_value")Parameters such asscope,resourceoraudienceor any other parameter that may be required by the AS can be passed
as keyword parameters. Those will be included in the token request that is sent to the AS.scopeis not mandatory at
client level (but it might be required by your AS to serve your request).As Auth HandlerYou can use theOAuth2ClientCredentialsAuthauth handler. It takes anOAuth2Clientas parameter, and the additional kwargs to pass to the token endpoint:importrequestsfromrequests_oauth2clientimportOAuth2Client,OAuth2ClientCredentialsAuthoauth2client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",auth=("client_id","client_secret"),)auth=OAuth2ClientCredentialsAuth(oauth2client,scope="myscope",resource="https://myapi.local")# use it like this:requests.get("https://myapi.local/resource",auth=auth)# or like this:session=requests.Session()session.auth=authresp=session.get("https://myapi.local/resource")Once again, extra parameters such asscope,resourceoraudienceare allowed if required.When you send your first request,OAuth2ClientCredentialsAuthwill automatically retrieve an access token from the AS using the Client Credentials grant, then will include it in the
request. Next requests will use the same token, as long as it is valid. A new token will be automatically retrieved once
the previous one is expired.Authorization Code GrantObtaining tokens with the Authorization code grant is made in 3 steps:your application must open a specific url called theAuthentication Requestin a browser.your application must obtain and validate theAuthorization Response, which is a redirection back to your
application that contains anAuthorization Codeas parameter. This redirect back (often called "callback") is
initiated by the Authorization Server after any necessary interaction with the user is complete (Registration, Login,
Profile completion, Multi-Factor Authentication, Authorization, Consent, etc.)your application must then exchange this Authorization Code for anAccess Token, with a request to the Token
Endpoint.requests_oauth2client, and more specificallyOAuth2Clientwill help you with all those steps, as described below.Generating Authorization RequestsTo be able to use the Authorization Code grant, you need two urls:the URL for Authorization Endpoint, which is the url where you must send your Authorization Requeststhe Redirect URI, which is the url pointing to your application, where the Authorization Server will reply with
Authorization ResponseYou can declare those urls when initializing your OAuth2Client instance. Then you can generate valid Authorization
Requests by calling the method.authorization_request():fromrequests_oauth2clientimportOAuth2Clientclient=OAuth2Client(token_endpoint="https://url.to.the/token_endoint",authorization_endpoint="https://url.to.the/authorization_endpoint",redirect_uri="https://url.to.my.application/redirect_uri",client_id="client_id",client_secret="client_secret",)az_request=client.authorization_request(scope="openid email profile")print(az_request)# this will look like this, with line feeds for display purposes only:# https://url.to.the/authorization_endpoint# ?client_id=client_id# &redirect_uri=https%3A%2F%2Furl.to.my.application%2Fredirect_uri# &response_type=code# &scope=openid+email+profile# &state=FBx9mWeLwoKGgG76vhi6v61-4mgxmgZhtWIa7aTffdY# &nonce=iHZJokhkGOAojff1tdknRyz9mPZyy5vq9JDlVaUHyqk# &code_challenge=TG7qgdyKnwUPuoQ6NNJRlLMoHbeVmJlB8g0VOcfQEkc# &code_challenge_method=S256# you can send the user to that url with:importwebbrowserwebbrowser.open(az_request.uri)Note that thestate,nonceandcode_challengeparameters are generated with secure random values by default.
Should you wish to use your own values, you can pass them as parameters toOAuth2Client.authorization_request(). For
PKCE, you need to pass your generatedcode_verifier, and thecode_challengewill automatically be derived from it.
If you don't want to use PKCE, you can passcode_challenge_method=Nonewhen initializing yourOAuth2Client.Validating the Authorization ResponseOnce you have redirected the user browser to the Authorization Request URI, and after the user is successfully
authenticated and authorized, plus any other extra interactive step is complete, the AS will respond with a redirection
to your redirect_uri. That is theAuthorization Response. It contains several parameters that must be retrieved by
your client. TheAuthorization Codeis one of those parameters, but you must also validate that thestatematches
your request. You can do this with:# using the `az_request` as defined aboveresponse_uri=input("Please enter the full url and/or params obtained on the redirect_uri: ")az_response=az_request.validate_callback(response_uri)This auth_response is anAuthorizationResponseinstance and contains everything that is needed for your application to
complete the authentication and get its tokens from the AS.Exchanging code for tokensOnce you have obtained the AS response, containing an authorization code, your application must exchange it for actual
Token(s).To exchange a code for Access and/or ID tokens, use theOAuth2Client.authorization_code()method. If you have obtained an AuthorizationResponse as described above, you can simply do:token=oauth2client.authorization_code(az_response)This will automatically include thecode,redirect_uriandcode_verifierparameters in the Token Request, as
expected by the AS. You may include extra parameters if required, or you may pass your own parameters, without using anAuthorizationResponseinstance, like this:token=oauth2client.authorization_code(code=code,code_verifier=code_verifier,redirect_uri=redirect_uri,custom_param=custom_value,)As Auth HandlerTheOAuth2AuthorizationCodeAuthhandler takes anOAuth2Clientand an authorization code as parameter, plus whatever additional keyword parameters are
required by your Authorization Server:fromrequests_oauth2clientimportOAuth2Client,ApiClient,OAuth2AuthorizationCodeAuthoauth2client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",authorization_endpoint="https://url.to.the/authorization_endpoint",auth=("client_id","client_secret"),)api_client=ApiClient("https://your.protected.api/endpoint",auth=OAuth2AuthorizationCodeAuth(oauth2client,"my_authorization_code",),)# any request using api_client will trigger exchanging the code for an access_token, which is then cached, and refreshed later if neededresp=api_client.post(data={...})OAuth2AuthorizationCodeAuthwill take care of refreshing the token automatically once it is expired, using the refresh token, if available.Note on AuthorizationRequestAuthorization Requests generated byOAuth2Client.authorization_request()are instance of the classAuthorizationRequest.
You can also use that class directly to generate your requests, but in that case you need to supply your Authorization
Endpoint URI, yourclient_id,redirect_uri, etc. You can access every parameter from anAuthorizationRequestinstance, as well as the generatedcode_verifier, as attributes of this instance. Once an Authorization Request URL is
generated, it your application responsibility to redirect or otherwise send the user to that URL. You may use thewebbrowsermodule from Python standard library to do so. Here is an example for generating Authorization Requests:fromrequests_oauth2clientimportAuthorizationRequestaz_request=AuthorizationRequest("https://url.to.the/authorization_endpoint",client_id="my_client_id",redirect_uri="http://localhost/callback",# this redirect_uri is specific to your appscope="openid email profile",# extra parameters such as `resource` can be included as well if required by your ASresource="https://my.resource.local/api",)print(az_request)# this request will look like this, with line breaks for display purposes only# https://url.to.the/authorization_endpoint# ?client_id=my_client_id# &redirect_uri=http%3A%2F%2Flocalhost%callback# &response_type=code# &state=kHWL4VwcbUbtPR4mtht6yMAGG_S-ZcBh5RxI_IGDmJc# &nonce=mSGOS1M3LYU9ncTvvutoqUR4n1EtmaC_sQ3db4dyMAc# &scope=openid+email+profile# &code_challenge=W3n02f6xUKoDVbmhWEWz3h780b-Ci6ucnBS_d7nogmQ# &code_challenge_method=S256# &resource=https%3A%2F%2Fmy.resource.local%2Fapiprint(az_request.code_verifier)# 'gYK-ZnQfoat2bghwed7oEz--wvn4D70ksJ5GuWO9sXXygZ7PMnUlSpBmMCcNRHxdgTS9m_roYwGxF6HQxIqZVwXmxRJUziFHUFxDrNuUIjCJCx6gBhPlpFbUXulB1fo2'Device Authorization GrantHelpers for the Device Authorization Grant are also included. To get device and user codes, read the response attributes
(including Device Code, User Code, Verification URI, etc.), then pooling the Token Endpoint:fromrequests_oauth2clientimport(OAuth2Client,DeviceAuthorizationPoolingJob,BearerToken,)client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",device_authorization_endpoint="https://url.to.the/device_authorization_endpoint",auth=("client_id","client_secret"),)da_resp=client.authorize_device()# `da_resp` contains the Device Code, User Code, Verification URI and other info returned by the AS:da_resp.device_codeda_resp.user_codeda_resp.verification_urida_resp.verification_uri_completeda_resp.expires_at# just like for BearerToken, expiration is tracked by requests_oauth2clientda_resp.interval# Send/show the Verification Uri and User Code to the user. He must use a browser to visit that url, authenticate and# input the User Code.# You can then request the Token endpoint to check if the user successfully authorized your device like this:pool_job=DeviceAuthorizationPoolingJob(client,da_resp)resp=NonewhilerespisNone:resp=pool_job()assertisinstance(resp,BearerToken)DeviceAuthorizationPoolingJobwill automatically obey the pooling period. Everytime you callpool_job(), it will wait the appropriate number of
seconds as indicated by the AS, and will apply slow_down requests.As Auth HandlerUseOAuth2DeviceCodeAuthas auth handler to exchange a device code for an access token:fromrequests_oauth2clientimportApiClient,OAuth2DeviceCodeAuth,OAuth2Clientclient=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",device_authorization_endpoint="https://url.to.the/device_authorization_endpoint",auth=("client_id","client_secret"),)device_auth_resp=client.authorize_device()# expose user_code and verification_uri or verification_uri_complete to the userdevice_auth_resp.user_codedevice_auth_resp.verification_uridevice_auth_resp.verification_uri_complete# then try to send your request with a OAuth2DeviceCodeAuth handler# this will pool the token endpoint until the user authorize the deviceapi_client=ApiClient("https://your.protected.api/endpoint",auth=OAuth2DeviceCodeAuth(client,device_auth_resp),)resp=api_client.post(data={...})# first call will hang until the user authorizes your app and the token endpoint returns a token.Client-Initiated BackChannel Authentication (CIBA)To initiate a BackChannel Authentication against the dedicated endpoint, read the response attributes, and pool the
Token Endpoint until the end-user successfully authenticates:fromrequests_oauth2clientimport(OAuth2Client,BearerToken,BackChannelAuthenticationPoolingJob,)client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",backchannel_authentication_endpoint="https://url.to.the/backchannel_authorization_endpoint",auth=("client_id","client_secret"),)ba_resp=client.backchannel_authentication_request(scope="openid email profile",login_hint="user@example.net",)# `ba_resp` will contain the response attributes as returned by the AS, including an `auth_req_id`:ba_resp.auth_req_idba_resp.expires_in# decreases as times flyba_resp.expires_at# a datetime to keep track of the expiration date, based on the "expires_in" returned by the ASba_resp.interval# the pooling interval indicated by the ASba_resp.custom# if the AS respond with additional attributes, they are also accessiblepool_job=BackChannelAuthenticationPoolingJob(client,ba_resp)resp=NonewhilerespisNone:resp=pool_job()assertisinstance(resp,BearerToken)Hints by the AS to slow down pooling will automatically be obeyed.Token ExchangeTo send a token exchange request, use theOAuth2Client.token_exchange()method:fromrequests_oauth2clientimportOAuth2Client,ClientSecretJwtclient=OAuth2Client("https://url.to.the/token_endpoint",auth=ClientSecretJwt("client_id","client_secret"),)token=client.token_exchange(subject_token="your_token_value",subject_token_type="urn:ietf:params:oauth:token-type:access_token",)As with the other grant-type specific methods, you may specify additional keyword parameters, that will be passed to the
token endpoint, including any standardised attribute likeactor_tokenoractor_token_type, or any custom parameter.
There are short names for token types, that will be automatically translated to standardised types:token=client.token_exchange(subject_token="your_token_value",subject_token_type="access_token",# will be automatically replaced by "urn:ietf:params:oauth:token-type:access_token"actor_token="your_actor_token",actor_token_type="id_token",# will be automatically replaced by "urn:ietf:params:oauth:token-type:id_token")Or to make it even easier, types can be guessed based on the supplied subject or actor token:fromrequests_oauth2clientimportBearerToken,ClientSecretJwt,IdToken,OAuth2Clientclient=OAuth2Client("https://url.to.the/token_endpoint",auth=ClientSecretJwt("client_id","client_secret"),)token=client.token_exchange(subject_token=BearerToken("your_token_value"),# subject_token_type will be "urn:ietf:params:oauth:token-type:access_token"actor_token=IdToken("your_actor_token"),# actor_token_type will be "urn:ietf:params:oauth:token-type:id_token")Supported Client Authentication Methodsrequests_oauth2clientsupports several client authentication methods, as defined in multiple OAuth2.x standards. You
select the appropriate method to use when initializing yourOAuth2Client, with theauthparameter. Once initialized,
a client will automatically use the configured authentication method every time it sends a requested to an endpoint that
requires client authentication. You don't have anything else to do afterwards.Client Secret BasicWithclient_secret_basic,client_idandclient_secretare included in clear-text in theAuthorizationheader
when sending requests to the Token Endpoint. To use it, just pass aClientSecretBasic(client_id, client_secret)asauthparameter:fromrequests_oauth2clientimportOAuth2Client,ClientSecretBasicclient=OAuth2Client("https://url.to.the/token_endpoint",auth=ClientSecretBasic("client_id","client_secret"),)Client Secret PostWithclient_secret_post,client_idandclient_secretare included as part of the body form data. To use it, pass
aClientSecretPost(client_id, client_secret)asauthparameter. This is the default when you pass a tuple(client_id, client_secret)asauthwhen initializing
anOAuth2Client:fromrequests_oauth2clientimportOAuth2Client,ClientSecretPostclient=OAuth2Client("https://url.to.the/token_endpoint",auth=ClientSecretPost("client_id","client_secret"),)# orclient=OAuth2Client("https://url.to.the/token_endpoint",auth=("client_id","client_secret"))# oroauth2client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",client_id="my_client_id",client_secret="my_client_secret",)Client Secret JWTWithclient_secret_jwt, the client generates an ephemeral JWT assertion including information about itself
(client_id), the AS (url of the endpoint), and an expiration date a few seconds in the future. To use it, pass aClientSecretJwt(client_id, client_secret)asauthparameter. Assertion generation is entirely automatic, you don't have anything to do:fromrequests_oauth2clientimportOAuth2Client,ClientSecretJwtclient=OAuth2Client("https://url.to.the/token_endpoint",auth=ClientSecretJwt("client_id","client_secret"),)This method is more secure than the 2 previous, because only ephemeral credentials are transmitted, which limits the
possibility for interception and replay of the Client Secret. But that Client Secret still needs to be shared between
the AS and Client owner(s).Private Key JWTWithprivate_key_jwt, client uses a JWT assertion that is just like the one forclient_secret_jwt, but it is
signed with anasymmetrickey. To use it, you need a private signing key, in adictthat matches the JWK format, or
as an instance ofjwskate.Jwk. The matching public key must be registered for your client on AS side. Once you have
that, using this auth method is simple with thePrivateKeyJwt(client_id, private_jwk)auth handler:fromrequests_oauth2clientimportOAuth2Client,PrivateKeyJwtprivate_jwk={"kid":"mykid","kty":"RSA","e":"AQAB","n":"...","d":"...","p":"...","q":"...","dp":"...","dq":"...","qi":"...",}client=OAuth2Client("https://url.to.the/token_endpoint",auth=PrivateKeyJwt("client_id",private_jwk))# orclient=OAuth2Client("https://url.to.the/token_endpoint",auth=("client_id",private_jwk))# orclient=OAuth2Client("https://url.to.the/token_endpoint",client_id="client_id",private_jwk=private_jwk)This method can be considered more secure than those relying on a client secret, because only ephemeral credentials are
sent over the wire, and it uses asymmetric cryptography: the signing key is generated by the client, and only the public
key is known by the AS. Transmitting that public key between owner(s) of the client and of the AS is much easier than
transmitting the Client Secret, which is a shared key that must be considered as confidential.NoneThe latest Client Authentication Method,none, is for Public Clients which do not authenticate to the Token
Endpoint. Those clients only include theirclient_idin body form data, without any authentication credentials. UsePublicApp(client_id):fromrequests_oauth2clientimportOAuth2Client,PublicAppclient=OAuth2Client("https://url.to.the/token_endpoint",auth=PublicApp("app_client_id"))Token RevocationOAuth2Clientcan send revocation requests to a Revocation Endpoint. You need to provide a Revocation Endpoint URI when
creating theOAuth2Client. TheOAuth2Client.revoke_token()method and its specialized aliases.revoke_access_token()and.revoke_refresh_token()are then available:fromrequests_oauth2clientimportOAuth2Client,ClientSecretJwtoauth2client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",revocation_endpoint="https://url.to.the/revocation_endpoint",auth=ClientSecretJwt("client_id","client_secret"),)oauth2client.revoke_token("mytoken",token_type_hint="access_token")oauth2client.revoke_access_token("mytoken")# will automatically add token_type_hint=access_tokenoauth2client.revoke_refresh_token("mytoken")# will automatically add token_type_hint=refresh_tokenBecause Revocation Endpoints usually don't return meaningful responses, those methods return a boolean. This boolean
indicates that a request was successfully sent and no error was returned. If the Authorization Server returns a
non-successful HTTP code, but no standardised error message, it will returnFalse. If the Authorization Server
actually returns a standardised error, an exception will be raised instead, like the other methods fromOAuth2Client.Token IntrospectionOAuth2Clientcan send requests to a Token Introspection Endpoint. You need to provide an Introspection Endpoint URI
when creating theOAuth2Client. TheOAuth2Client.introspect_token()method is then available:fromrequests_oauth2clientimportOAuth2Client,ClientSecretJwtoauth2client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",introspection_endpoint="https://url.to.the/introspection_endpoint",auth=ClientSecretJwt("client_id","client_secret"),)resp=oauth2client.introspect_token("mytoken",token_type_hint="access_token")It returns whatever data is returned by the introspection endpoint (if it is a JSON, its content is returned decoded).UserInfo RequestsOAuth2Clientcan send requests to an UserInfo Endpoint. You need to provide an UserInfo Endpoint URI when creating theOAuth2Client. TheOAuth2Client.userinfo())
method is then available:fromrequests_oauth2clientimportOAuth2Client,ClientSecretJwtoauth2client=OAuth2Client(token_endpoint="https://url.to.the/token_endpoint",userinfo_endpoint="https://url.to.the/userinfo_endpoint",auth=ClientSecretJwt("client_id","client_secret"),)resp=oauth2client.userinfo("mytoken")It returns whatever data is returned by the userinfo endpoint (if it is a JSON, its content is returned decoded).Initializing an OAuth2Client from a discovery documentYou can initialize anOAuth2Clientwith the endpoint URIs mentioned in a standardised discovery document with theOAuth2Client.from_discovery_endpoint()class method:fromrequests_oauth2clientimportOAuth2Client,ClientSecretJwtoauth2client=OAuth2Client.from_discovery_endpoint("https://url.to.the/.well-known/openid-configuration",auth=ClientSecretJwt("client_id","client_secret"),)This will fetch the document from the specified URI, then will decode it and initialize anOAuth2Clientpointing to
the appropriate endpoint URIs.Specialized API ClientUsing APIs usually involves multiple endpoints under the same root url, with a common authentication method. To make it
easier,requests_oauth2clientincludes arequests.Sessionwrapper calledApiClient, which takes the root API url
as parameter on initialization. You can then send requests to different endpoints by passing their relative path instead
of the full url.ApiClientalso accepts anauthparameter with an AuthHandler. You can pass any of the OAuth2 Auth
Handler from this module, or anyrequests-compatibleAuthentication Handler. Which makes it
very easy to call APIs that are protected with an OAuth2 Client Credentials Grant:fromrequests_oauth2clientimportOAuth2Client,ApiClient,OAuth2ClientCredentialsAuthoauth2client=OAuth2Client("https://url.to.the/token_endpoint",("client_id","client_secret"))api=ApiClient("https://myapi.local/root",auth=OAuth2ClientCredentialsAuth(oauth2client))# will actually send a GET to https://myapi.local/root/resource/fooresp=api.get("/resource/foo")Note thatApiClientwill never send requests "outside" its configured root url, unless you specifically give it a full
url at request time. The leading/in/resourceabove is optional. A leading/will not "reset" the url path to
root, which means that you can also write the relative path without the/and it will automatically be included:api.get("resource/foo")# will also send a GET to https://myapi.local/root/resource/fooYou may also pass the path as an iterable of strings (or string-able objects), in which case they will be joined with a/and appended to the url path:# will send a GET to https://myapi.local/root/resource/fooapi.get(["resource","foo"])# will send a GET to https://myapi.local/root/users/1234/detailsapi.get(["users",1234,"details"])You can also use a syntax based on__getattr__or__getitem__:api.resource.get()# will send a GET to https://myapi.local/root/resourceapi["my-resource"].get()# will send a GET to https://myapi.local/root/my-resourceBoth__getattr__and__getitem__return a newApiClientinitialised on the new base_url. So you can easily call
multiple sub-resources on the same API this way:fromrequests_oauth2clientimportApiClientapi=ApiClient("https://myapi.local")users_api=api.usersuser=users_api.get("userid")# GET https://myapi.local/users/useridother_user=users_api.get("other_userid")# GET https://myapi.local/users/other_useridresources_api=api.resourcesresources=resources_api.get()# GET https://myapi.local/resourcesApiClientwill, by default, raise exceptions whenever a request returns an error status. You can disable that by
passingraise_for_status=Falsewhen initializing yourApiClient:fromrequests_oauth2clientimportApiClientapi=ApiClient("http://httpstat.us",raise_for_status=False)# raise_for_status defaults to Trueresp=api.get("500")assertrespisnotNone# without raise_for_status=False, a requests.exceptions.HTTPError exception would be raised insteadYou may override this at request time:# raise_for_status at request-time overrides the value defined at init-timeresp=api.get("500",raise_for_status=True)You can access the underlyingrequests.Sessionwith the session attribute, and you can provide an already existing and
configuredSessioninstance at init time:importrequestsfromrequests_oauth2clientimportApiClientsession=requests.Session()session.proxies={"https":"http://localhost:3128"}api=ApiClient("https://myapi.local/resource",session=session)assertapi.session==sessionVendor-Specific clientsrequests_oauth2clientbeing flexible enough to handle most use cases, you should be able to use any AS by any vendor
as long as it supports OAuth 2.0.You can however create a subclass ofOAuth2ClientorApiClientto make it easier to use with specific Authorization
Servers or APIs. The sub-modulerequests_oauth2client.vendor_specificincludes such classes forAuth0:fromrequests_oauth2client.vendor_specificimportAuth0Client,Auth0ManagementApiClienta0client=Auth0Client("mytenant.eu",("client_id","client_secret"))# this will automatically initialize the token endpoint to https://mytenant.eu.auth0.com/oauth/token# and other endpoints accordinglytoken=a0client.client_credentials(audience="audience")# this is a wrapper around Auth0 Management APIa0mgmt=Auth0ManagementApiClient("mytenant.eu",("client_id","client_secret"))myusers=a0mgmt.get("users")