Authentication and Throttling#
This document primarily serves to document our additions to DRF’s built-in throttling support. In order to accomplish this, some basic facts about our OAuth flow and configuration must also be explained.
This document deals primarily with the server’s perspective of the OAuth flow and assumes you are familiar with the user’s perspective. If you are not familiar with the user’s perspective, please study the Register and Authenticate section of the API documentation.
Furthermore, this section assumes at least a surface level understanding of the
django-oauth-toolkit
library and its concepts. In particular, it is necessary
to understand the
Application
concept, the docs for which can be found here.
Flow#
When a user makes the initial request to create their OAuth application, we
create a ThrottledApplication
model to associate to the likewise generated
OAuth client. Whenever the user generates a new token using their client ID and
key pair, it is automatically associated with the ThrottledApplication
for the
client via a
foreign key referencing the application on the access token.
This allows us to retrieve the application for the token using just the token
itself.
ThrottledApplication
#
The ThrottledApplication
is an extension of the base AbstractApplication
class from django-oauth-toolkit
that adds an additional concept of a
rate_limit_model
. Each rate limit model can be thought of as a “tiers” of rate
limiting that the Openverse API supports.
Rate limit models (tiers)#
The following tiers exist:
standard
: The default rate limit that anyone is able to unlock simply by authenticating. Slightly higher and much more useful limit for an application.enhanced
: A selectively granted rate limit that allows for significantly higher burst and sustained requests.exempt
: A rate limit model that exists purely to accommodate internal infrastructural needs. For example, the server that renders the frontend can use tokens of this tier to prevent itself from being rate limited by the API during server side rendering. Likewise, when we need to circumvent the throttling to do load testing, we use a key of this tier.
Throttles#
Each of these tiers also have corresponding throttle classes that are configured
in settings.py
. Each throttle class declares a “scope” applied to it. The
“scope” defines the rate. The throttle class merely indicates to the view
whether it itself applies to the incoming request. If it does not, then it
returns a None
cache key from get_cache_key
and the view ignores the
throttle class. If the throttle does apply to the request, then it returns a
formatted cache key that the base DRF view then uses to determine whether the
requester is still within the limits of their scope.
To further understand this concept, it may be helpful to read the code for
SimpleRateThrottle
and the
check_throttles
method of the DRF base view class.
Each of the tiers above have their own scope namespace. For example, enhanced
applications will use the scopes namespaced with
enhanced_oauth2_client_credentials
. To determine which scope a given
authenticated request should have applied to it, we need to determine which
application rate limit tier it belongs to. To simplify this abstract process, we
use the OAuth2IdRateThrottle
base class. All it does is take an incoming
authenticated request, retrieve the application for the given access token, and
then create a cache key based on the client ID and scope if the class is
configured to handle the application’s rate limit tier.
Individual tiers have complementary subclasses of OAuth2IdRateThrottle
that
configure which scope to apply to a particular rate limit tier. Please refer to
the catalog.api.utils.throttle
module for example implementations of this
pattern.