# 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](https://api.openverse.engineering/v1/#section/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](https://django-oauth-toolkit.readthedocs.io/en/latest/advanced_topics.html#extending-the-application-model).

## 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](https://django-oauth-toolkit.readthedocs.io/en/latest/models.html#oauth2_provider.models.AbstractAccessToken).
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`](https://github.com/encode/django-rest-framework/blob/129890ab1bbbba2deb96b8e30675dfb1060d7615/rest_framework/throttling.py#L50)
and the
[`check_throttles` method of the DRF base view class](https://github.com/encode/django-rest-framework/blob/101aff6c43f6fa96174683e050988428143d1040/rest_framework/views.py#L352-L371).

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.
