requests_oauth2client
is 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 famous requests HTTP client module.
It can act as an OAuth 2.0 /
2.1 client, to automatically get and renew Access Tokens,
based on the
Client Credentials,
Authorization Code,
Refresh token,
Token Exchange,
JWT Bearer,
Device Authorization,
Resource Owner Password or
CIBA grants. Additional
grant types are easy to add if needed.
It also supports OpenID Connect 1.0,
PKCE,
Client Assertions,
Token Revocation and
Introspection,
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 a wrapper around requests.Session that 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 Google
oauth2client library.
Documentation
Full module documentation is available at https://guillp.github.io/requests_oauth2client/
Installation
requests_oauth2client
is available from PyPi, so installing it is
as easy as:
pip install requests_oauth2client
Usage
Everything from requests_oauth2client
is available from the root module, so you can import it like this:
from requests_oauth2client import *
Or you can import individual objects from this package as usual. Note that importing *
automatically imports
requests
, so no need to import it yourself.
Calling APIs with Access Tokens
If you already managed to obtain an access token for the API you want to call, you can simply convert it to an instance of BearerToken.
Instances of that class work as a requests
compatible auth handler.
import requests
from requests_oauth2client import BearerToken
token = BearerToken("my_access_token")
resp = requests.get("https://my.protected.api/endpoint", auth=token)
This authentication handler will add a Authorization: Bearer <access_token>
header in the request, with your access
token, properly formatted according to RFC6750.
Using an OAuth2Client
OAuth2Client offers 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 an OAuth2Client
.
To initialize an instance of OAuth2Client
, you only need a Token Endpoint URI from your AS, and the credentials for
your application, which are typically a client_id
and a client_secret
, usually also provided by the AS:
from requests_oauth2client import OAuth2Client
oauth2client = 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 by OAuth2Client
is Client Secret Post, but other standardised methods such as
Client Secret Basic, Client Secret JWT or Private Key JWT are supported as well. See
more about client authentication methods below.
Instead of providing each endpoint URL yourself, you may also
use the AS metadata endpoint URI, or the document data
itself, to initialize your OAuth 2.0 client with the appropriate endpoints.
Obtaining tokens
OAuth2Client has 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 a BearerToken if the request is successful, or raise an exception if it fails.
BearerToken contains 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 the
expires_in
hint as returned by the AS). This date is
accessible with the expires_at
attribute. - contain the Refresh Token, if returned by the AS, accessible with the
refresh_token
attribute. - contain the ID Token, if returned by the AS, accessible with the
ìd_token
attribute (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 syntax token["my.custom.attr"]
.
You can create such a BearerToken yourself if you need:
from requests_oauth2client import BearerToken
bearer_token = BearerToken(access_token="an_access_token", expires_in=60)
print(bearer_token)
print(bearer_token.expires_at)
assert not bearer_token.is_expired()
print(bearer_token.expires_in)
Note that the expires_in
indicator 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 the expires_at
property. You can
check if a token is expired with
bearer_token.is_expired().
You can use a BearerToken instance anywhere you can use an access_token as string.
Using OAuth2Client as a requests Auth Handler
While using OAuth2Client directly 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_oauth2client
contains several requests compatible Auth Handlers (as subclasses of
requests.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 a requests.Session,
or an ApiClient, which is a wrapper around Session
with a few enhancements as described below.
Client Credentials grant
To 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:
from requests_oauth2client import OAuth2Client
oauth2client = OAuth2Client(
token_endpoint="https://url.to.the/token_endpoint",
client_id="client_id",
client_secret="client_secret",
)
token = oauth2client.client_credentials(scope="myscope")
token = oauth2client.client_credentials(scope="myscope", resource="https://myapi.local")
token = oauth2client.client_credentials(audience="https://myapi.local")
token = oauth2client.client_credentials(scope="myscope", custom_param="custom_value")
Parameters such as scope
, resource
or audience
or 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. scope
is not mandatory at
client level (but it might be required by your AS to serve your request).
As Auth Handler
You can use the
OAuth2ClientCredentialsAuth
auth handler. It takes an OAuth2Client
as parameter, and the additional kwargs to pass to the token endpoint:
import requests
from requests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth
oauth2client = OAuth2Client(
token_endpoint="https://url.to.the/token_endpoint",
client_id="client_id",
client_secret="client_secret",
)
auth = OAuth2ClientCredentialsAuth(
oauth2client, scope="myscope", resource="https://myapi.local"
)
requests.get("https://myapi.local/resource", auth=auth)
session = requests.Session()
session.auth = auth
resp = session.get("https://myapi.local/resource")
Once again, extra parameters such as scope
, resource
or audience
are allowed if required.
When you send your first request,
OAuth2ClientCredentialsAuth
will 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.
You can configure a leeway, which is a period of time before the actual expiration, in seconds, when a new token will be
obtained. This may help getting continuous access to the API when the client and API clocks are slightly out of sync.
Use the parameter leeway
to OAuth2ClientCredentialsAuth
:
from requests_oauth2client import OAuth2ClientCredentialsAuth
auth = OAuth2ClientCredentialsAuth(
oauth2client,
scope="myscope",
leeway=30,
)
Authorization Code Grant
Obtaining tokens using the Authorization code grant is made in 3 steps:
-
your application must open a specific url called the Authentication Request in a browser.
-
your application must obtain and validate the Authorization Response, which is a redirection back to your
application that contains an Authorization Code as 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 an Access Token, with a request to the Token
Endpoint.
Using an OAuth2Client
will help you with all those steps, as described below.
Generating Authorization Requests
To be able to use the Authorization Code grant, you need 2 (optionally 3) URIs:
- the URL for Authorization Endpoint, which is the url where you must send your Authorization Requests
- the Redirect URI, which is the url pointing to your application, where the Authorization Server will reply with
Authorization Response
- optionally, the issuer identifier, if your AS uses
Issuer Identification.
You can declare those URIs when initializing your OAuth2Client
instance, or you can
use the AS discovery endpoint to initialize those URLs
automatically. Then you can generate valid Authorization Requests by calling the method .authorization_request()
, with
the request specific parameters, such as scope
, state
, nonce
as parameter:
from requests_oauth2client import OAuth2Client
client = 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)
import webbrowser
webbrowser.open(az_request.uri)
Note that the state
, nonce
and code_challenge
parameters are generated with secure random values by default.
Should you wish to use your own values, you can pass them as parameters to OAuth2Client.authorization_request()
. For
PKCE, you need to pass your generated code_verifier
, and the code_challenge
will automatically be derived from it.
If you want to disable PKCE, you can pass code_challenge_method=None
when initializing your OAuth2Client
.
Validating the Authorization Response
Once 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 the Authorization Response. It contains several parameters that must be retrieved by
your client. The Authorization Code is one of those parameters, but you must also validate that the state matches
your request; if using AS Issuer Identification, you must also validate
that the issuer matches what is expected. You can do this with:
response_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 an AuthorizationResponse
instance and contains everything that is needed for your application
to complete the authentication and get its tokens from the AS.
Exchanging code for tokens
Once 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 the
OAuth2Client.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 the code
, redirect_uri
and code_verifier
parameters 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 an
AuthorizationResponse
instance, like this:
token = oauth2client.authorization_code(
code=code,
code_verifier=code_verifier,
redirect_uri=redirect_uri,
custom_param=custom_value,
)
As Auth Handler
The
OAuth2AuthorizationCodeAuth
handler takes an OAuth2Client and an authorization code as parameter, plus whatever additional keyword parameters are
required by your Authorization Server:
from requests_oauth2client import OAuth2Client, ApiClient, OAuth2AuthorizationCodeAuth
oauth2client = 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",
),
)
resp = api_client.post(data={...})
OAuth2AuthorizationCodeAuth
will take care of refreshing the token automatically once it is expired, using the refresh token, if available.
Note on AuthorizationRequest
Authorization Requests generated by OAuth2Client.authorization_request()
are instance of the class
AuthorizationRequest
.
You can also use that class directly to generate your requests, but in that case you need to supply your Authorization
Endpoint URI, your client_id
, redirect_uri
, etc. You can access every parameter from an AuthorizationRequest
instance, as well as the generated code_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 the
webbrowser
module from Python standard library to do so. Here is an example for generating Authorization Requests:
from requests_oauth2client import AuthorizationRequest
az_request = AuthorizationRequest(
"https://url.to.the/authorization_endpoint",
client_id="my_client_id",
redirect_uri="http://localhost/callback",
scope="openid email profile",
resource="https://my.resource.local/api",
)
print(
az_request
)
print(az_request.code_verifier)
Device Authorization Grant
Helpers 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:
from requests_oauth2client import (
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.device_code
da_resp.user_code
da_resp.verification_uri
da_resp.verification_uri_complete
da_resp.expires_at
da_resp.interval
pool_job = DeviceAuthorizationPoolingJob(client, da_resp)
resp = None
while resp is None:
resp = pool_job()
assert isinstance(resp, BearerToken)
DeviceAuthorizationPoolingJob
will automatically obey the pooling period. Everytime you call pool_job()
, it will wait the appropriate number of
seconds as indicated by the AS, and will apply slow_down requests.
As Auth Handler
Use
OAuth2DeviceCodeAuth
as auth handler to exchange a device code for an access token:
from requests_oauth2client import ApiClient, OAuth2DeviceCodeAuth, OAuth2Client
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"),
)
device_auth_resp = client.authorize_device()
device_auth_resp.user_code
device_auth_resp.verification_uri
device_auth_resp.verification_uri_complete
api_client = ApiClient(
"https://your.protected.api/endpoint",
auth=OAuth2DeviceCodeAuth(client, device_auth_resp),
)
resp = api_client.post(
data={...}
)
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:
from requests_oauth2client import (
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.auth_req_id
ba_resp.expires_in
ba_resp.expires_at
ba_resp.interval
ba_resp.custom
pool_job = BackChannelAuthenticationPoolingJob(client, ba_resp)
resp = None
while resp is None:
resp = pool_job()
assert isinstance(resp, BearerToken)
Hints by the AS to slow down pooling will automatically be obeyed.
Token Exchange
To send a token exchange request, use the
OAuth2Client.token_exchange()
method:
from requests_oauth2client import OAuth2Client, ClientSecretJwt
client = 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 like actor_token
or actor_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",
actor_token="your_actor_token",
actor_token_type="id_token",
)
Or to make it even easier, types can be guessed based on the supplied subject or actor token:
from requests_oauth2client import BearerToken, ClientSecretJwt, IdToken, OAuth2Client
client = OAuth2Client(
"https://url.to.the/token_endpoint",
auth=ClientSecretJwt("client_id", "client_secret"),
)
token = client.token_exchange(
subject_token=BearerToken(
"your_token_value"
),
actor_token=IdToken(
"your_actor_token"
),
)
Supported Client Authentication Methods
requests_oauth2client
supports several client authentication methods, as defined in multiple OAuth2.x standards. You
select the appropriate method to use when initializing your OAuth2Client, with the auth
parameter. 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 Basic
With client_secret_basic, client_id
and client_secret
are included in clear-text in the Authorization
header
when sending requests to the Token Endpoint. To use it, just pass a
ClientSecretBasic(client_id, client_secret)
as auth
parameter:
from requests_oauth2client import OAuth2Client, ClientSecretBasic
client = OAuth2Client(
"https://url.to.the/token_endpoint",
auth=ClientSecretBasic("client_id", "client_secret"),
)
Client Secret Post
With client_secret_post, client_id
and client_secret
are included as part of the body form data. To use it, pass
a
ClientSecretPost(client_id, client_secret)
as auth
parameter. This is the default when you pass a tuple (client_id, client_secret)
as auth
when initializing
an OAuth2Client
:
from requests_oauth2client import OAuth2Client, ClientSecretPost
client = OAuth2Client(
"https://url.to.the/token_endpoint",
auth=ClientSecretPost("client_id", "client_secret"),
)
client = OAuth2Client(
"https://url.to.the/token_endpoint", auth=("client_id", "client_secret")
)
oauth2client = OAuth2Client(
token_endpoint="https://url.to.the/token_endpoint",
client_id="my_client_id",
client_secret="my_client_secret",
)
Client Secret JWT
With client_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 a
ClientSecretJwt(client_id, client_secret)
as auth
parameter. Assertion generation is entirely automatic, you don't have anything to do:
from requests_oauth2client import OAuth2Client, ClientSecretJwt
client = 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 JWT
With private_key_jwt, client uses a JWT assertion that is just like the one for client_secret_jwt, but it is
signed with an asymmetric key. To use it, you need a private signing key, in a dict
that matches the JWK format, or
as an instance of jwskate.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 the
PrivateKeyJwt(client_id, private_jwk)
auth handler:
from requests_oauth2client import OAuth2Client, PrivateKeyJwt
private_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)
)
client = OAuth2Client(
"https://url.to.the/token_endpoint", auth=("client_id", private_jwk)
)
client = 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.
None
The latest Client Authentication Method, none, is for Public Clients which do not authenticate to the Token
Endpoint. Those clients only include their client_id
in body form data, without any authentication credentials. Use
PublicApp(client_id)
:
from requests_oauth2client import OAuth2Client, PublicApp
client = OAuth2Client(
"https://url.to.the/token_endpoint", auth=PublicApp("app_client_id")
)
Token Revocation
OAuth2Client can send revocation requests to a Revocation Endpoint. You need to provide a Revocation Endpoint URI when
creating the OAuth2Client. The
OAuth2Client.revoke_token()
method and its specialized aliases
.revoke_access_token()
and
.revoke_refresh_token()
are then available:
from requests_oauth2client import OAuth2Client, ClientSecretJwt
oauth2client = 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"
)
oauth2client.revoke_refresh_token(
"mytoken"
)
Because 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 return False
. If the Authorization Server
actually returns a standardised error, an exception will be raised instead, like the other methods from OAuth2Client
.
Token Introspection
OAuth2Client can send requests to a Token Introspection Endpoint. You need to provide an Introspection Endpoint URI
when creating the OAuth2Client
. The
OAuth2Client.introspect_token()
method is then available:
from requests_oauth2client import OAuth2Client, ClientSecretJwt
oauth2client = 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 Requests
OAuth2Client can send requests to an UserInfo Endpoint. You need to provide an UserInfo Endpoint URI when creating the
OAuth2Client
. The
OAuth2Client.userinfo())
method is then available:
from requests_oauth2client import OAuth2Client, ClientSecretJwt
oauth2client = 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 document
You can initialize an OAuth2Client with the endpoint URIs mentioned in a standardised discovery document with the
OAuth2Client.from_discovery_endpoint()
class method:
from requests_oauth2client import OAuth2Client, ClientSecretJwt
oauth2client = OAuth2Client.from_discovery_endpoint(
"https://url.to.the.as/.well-known/openid-configuration",
auth=ClientSecretJwt("client_id", "client_secret"),
)
oauth2client = OAuth2Client.from_discovery_endpoint(
issuer="https://url.to.the.as",
auth=ClientSecretJwt("client_id", "client_secret"),
)
This will fetch the document from the specified URI, then will decode it and initialize an OAuth2Client pointing to
the appropriate endpoint URIs.
If using the issuer
keyword arg, the URI to the discovery endpoint will be deduced from that identifier, and a check
will be made that the issuer
from the retrieved metadata document matches that value.
Specialized API Client
Using APIs usually involves multiple endpoints under the same root url, with a common authentication method. To make it
easier, requests_oauth2client
includes a requests.Session wrapper called ApiClient, 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. ApiClient also accepts an auth
parameter with an AuthHandler. You can pass any of the OAuth2 Auth
Handler from this module, or any requests-compatible
Authentication Handler. Which makes it
very easy to call APIs that are protected with an OAuth2 Client Credentials Grant:
from requests_oauth2client import OAuth2Client, ApiClient, OAuth2ClientCredentialsAuth
oauth2client = OAuth2Client(
"https://url.to.the/token_endpoint", ("client_id", "client_secret")
)
api = ApiClient(
"https://myapi.local/root", auth=OAuth2ClientCredentialsAuth(oauth2client)
)
resp = api.get("/resource/foo")
Note that ApiClient will never send requests "outside" its configured root url. The leading /
in /resource
above
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")
You 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:
api.get(["resource", "foo"])
api.get(["users", 1234, "details"])
You can also use a syntax based on __getattr__
or __getitem__
:
api.resource.get()
api["my-resource"].get()
Both __getattr__
and __getitem__
return a new ApiClient
initialised on the new base_url. So you can easily call
multiple sub-resources on the same API this way:
from requests_oauth2client import ApiClient
api = ApiClient("https://myapi.local")
users_api = api.users
user = users_api.get("userid")
other_user = users_api.get("other_userid")
resources_api = api.resources
resources = resources_api.get()
ApiClient will, by default, raise exceptions whenever a request returns an error status. You can disable that by
passing raise_for_status=False
when initializing your ApiClient:
from requests_oauth2client import ApiClient
api = ApiClient(
"http://httpstat.us", raise_for_status=False
)
resp = api.get("500")
assert resp is not None
You may override this at request time:
resp = api.get("500", raise_for_status=True)
You can access the underlying requests.Session
with the session attribute, and you can provide an already existing and
configured Session
instance at init time:
import requests
from requests_oauth2client import ApiClient
session = requests.Session()
session.proxies = {"https": "http://localhost:3128"}
api = ApiClient("https://myapi.local/resource", session=session)
assert api.session == session
Vendor-Specific clients
requests_oauth2client
is flexible enough to handle most use cases, so 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 of OAuth2Client or ApiClient to make it easier to use with specific Authorization
Servers or APIs. OAuth2Client has several extensibility points in the form of methods like
OAuth2Client.parse_token_response()
, OAuth2Client.on_token_error()
that implement response parsing, error handling,
etc.
from requests_oauth2client.vendor_specific import Auth0
a0client = Auth0.client(
"mytenant.eu", client_id="client_id", client_secret="client_secret"
)
token = a0client.client_credentials(audience="audience")
a0mgmt = Auth0.management_api_client(
"mytenant.eu", client_id="client_id", client_secret="client_secret"
)
myusers = a0mgmt.get("users")