stanford.green.oauth2¶
Library to interact with OAuth2 endpoints.
Overview¶
The stanford.green.oauth2
package provides classes to connect to
an OAuth2 Authorization Server and get an access token. These classes
support retries via the
exponential_backoff_ca Python package.
Once you
have the access token it is up to you to use it to make API calls.
There is built-in file-based caching to minimize the number of times you have to go out to the access token endpoint.
Examples¶
To connect to an OAuth2 Authorization Server and get an access token:
from exponential_backoff_ca import ExponentialBackoff
from stanford.green.oauth2 import AccessToken, ApiAccessTokenEndpoint
# The URL to get the token (provided by OAuth2 Authorization Service):
url = "https://api.endpoint.com/api/v1/token"
# The ApiAccessTokenEndpoint object requires an exponential backoff
# object to do the retries:
time_slot_secs = 3.0 # The number of seconds in each time slot.
num_iterations = 4 # The number of iterations.
limit_value = 10.0 # Don't wait any longer than this number of seconds.
exp_backoff = ExponentialBackoff(time_slot_secs, num_iterations,
limit_value=limit_value, debug=True)
# Define the ApiAccessTokenEndpoint object. The 'oauth2' tells the
# ApiAccessTokenEndpoint class that this is an OAuth2 access token
# endpoint.
client_id = 'username'
client_secret = 'password'
api_access = ApiAccessTokenEndpoint('oauth2', url, client_id, client_secret,
exp_backoff, scopes=['read', 'list'],
verbose=True)
# If you want to cache the token, set the "use_cache" flag to True:
# api_access = ApiAccessTokenEndpoint('oauth2', url, client_id, client_secret,
# exp_backoff, scopes=['read', 'list'],
# verbose=True, use_cache=True)
# Get the token.
access_token = api_access.get_token()
# This token can now be used with the API to do other operations.
To connect to an ACS-style API endpoint you use much the same code as above:
from exponential_backoff_ca import ExponentialBackoff
from stanford.green.oauth2 import AccessToken, ApiAccessTokenEndpoint
# The URL to get the token (provided by OAuth2 Authorization Service):
url = "https://api.endpoint.com/api/v1/token"
# The ApiAccessTokenEndpoint object requires an exponential backoff
# object to do the retries:
time_slot_secs = 3.0 # The number of seconds in each time slot.
num_iterations = 4 # The number of iterations.
limit_value = 10.0 # Don't wait any longer than this number of seconds.
exp_backoff = ExponentialBackoff(time_slot_secs, num_iterations,
limit_value=limit_value, debug=True)
# Define the ApiAccessTokenEndpoint object. The 'acs_api' tells the
# ApiAccessTokenEndpoint class that this is ACS API-style endpoint.
# Note that this kind of API access endpoint does not supply the
# scopes parameter.
client_id = 'username'
client_secret = 'password'
api_access = ApiAccessTokenEndpoint('acs_api', url, client_id, client_secret,
exp_backoff, verbose=True)
# Get the token.
access_token = api_access.get_token()
# This token can now be used with the API to do other operations.
- class stanford.green.oauth2.AccessToken(token: str, expires_at: datetime)¶
An object representing an OAuth access token returned by an OAuth Authorization Server.
- Parameters:
token (str) – the token string returned by an OAuth Authorization Server.
expires_at (datetime.datetime) – the date and time when the token
token
expires.
- property expires_at: datetime¶
Return the
expires_at
property (datetime.datetime object when token expires)
- expires_in() int ¶
The number of seconds until access token expires.
- Returns:
the number of seconds until access token expires
- Return type:
int
Note: if the token has expired this value will be negative.
- is_expired() bool ¶
Has the token expired?
- Returns:
True
if the token has expired,False
otherwise.- Return type:
bool
- zulu_time_string() str ¶
Return the
_expires_at
property as a Zulu time string
- class stanford.green.oauth2.ApiAccessTokenEndpoint(endpoint_type: str, url: str, client_id: str, client_secret: str, exp_backoff: ExponentialBackoff, timeout: float = 15.0, use_cache: bool = True, verbose: bool = False, grant_type: str = 'client_credentials', scopes: list[str] = [])¶
Represents an API endpoint returning an access token.
- Parameters:
endpoint_type (str) –
the type of API Access endpoint. Two types of endpoints are currently recognized:
acs_api
: a Stanford ACS-style API endpointoauth2
: a generic OAuth2 Authorization token endpoint
url (str) – the URL pointing to the OAuth Server’s access token endpoint. This is where we go to get the access token.
client_id (str) – the OAuth client’s identifier
client_secret (str) – the OAuth client’s secret (i.e., password)
exp_backoff (ExponentialBackoff) – an ExponentialBackoff object used for retrying access token retrieval.
timeout (float) – the maximum time in seconds to wait for each request attempt; default: 15.0.
use_cache (bool) – if set to
True
the access token will be cached; default:True
.verbose (bool) – if set to
True
progress information will be sent to standard output; default:False
.grant_type (str) – (only relevant if endpoint type is “oauth2”) the OAuth grant type; default: “client_credentials”
scopes (list[str]) – (only relevant if endpoint type is “oauth2”) a list of OAuth scopes the client wants access to; default: the empty list
- _get_token() AccessToken ¶
Get the access token from the token endpoint.
This is a simple wrapper function that calls the appropriate get-token function depending on the value of
self.endpoint_type
.
- _get_token_acs_api() AccessToken ¶
Get an access token from an ACS-API compatible token endpoint (no caching)
The JSON response from the ACS API token endpoint contains the token itself and two time-related attributes:
expires_at
: when the token expires in Zulu (UTC) time.expires_in
: the number of seconds from when the token was generated until it expires.
When creating the
AccessToken
object we convert the Zulu timeexpires_at
string into a Python timezone-aware datetime object that AccessToken requires.Furthermore,
AccessToken
calculates expires_in itself so we ignore the response’s expires_in value.
- _get_token_oauth2() AccessToken ¶
Get an access token from an OAuth2 endpoint (no caching)
The JSON response contains the token itself and the expires_in attribute
expires_in: the number of seconds from when the token was generated until it expires.
- cache_get() AccessToken ¶
Get the cached value.
- Returns:
the cached
AccessToken
object.- Return type:
AccessToken
- cache_set(value: AccessToken, expires_in: int) None ¶
Cache the
AccessToken
object.- Parameters:
value (
AccessToken
) – the AccessToken to cache.expires_in (int) – set the expiration to be
expires_in
seconds from now.
We use a file-based Cache which pickles the object before storage. To support this the AccessToken object has a custom Pickle instance (see
__setstate__
and__getstate
in theAccessToken
class in the source code).Note: this method only relevant if
self.use_cache
isTrue
.
- get_token(expires_at_override: datetime | None = None) AccessToken ¶
Get access token (uses cache if enabled).
- Parameters:
expires_at_override (Optional[datetime.datetime]) – a
datetime.datetime
to use instead of the actual expiration time; defaults toNone
.- Returns:
a valid (cached or otherwise)
AccessToken
object.- Return type:
AccessToken
If the value is cached, uses the cached value, otherwise gets the access token using
_get_token()
.There are circumstances (e.g., during unit testing) when we want to override the expires_at time that was set by the token API call. For those circumstances use the expires_at_override parameter.
- is_acs_api() bool ¶
- Returns:
True
ifself.endpoint_type
is set to “acs_api”,False
otherwise.- Return type:
bool
- is_oauth2() bool ¶
- Returns:
True
ifself.endpoint_type
is set to “oauth2”,False
otherwise.- Return type:
bool
- progress(msg: str) None ¶
Show a progress message