Management commands
===================

Django OAuth Toolkit exposes some useful management commands that can be run via shell or by other means such as cron
or :doc:`Celery <tutorial/tutorial_05>`.

.. _cleartokens:

cleartokens
~~~~~~~~~~~

The ``cleartokens`` management command allows the user to remove refresh tokens that can no longer be
used:

* those that have been idle longer than ``REFRESH_TOKEN_EXPIRE_SECONDS`` -- i.e. whose paired access
  token expired more than ``REFRESH_TOKEN_EXPIRE_SECONDS`` ago (see ``REFRESH_TOKEN_EXPIRE_SECONDS``
  for the idle-expiry semantics);
* those that have been revoked for longer than the ``REFRESH_TOKEN_GRACE_PERIOD_SECONDS`` setting; and
* orphaned refresh tokens -- non-revoked refresh tokens whose access token was deleted out of band,
  leaving nothing to refresh against. These are removed unconditionally, regardless of
  ``REFRESH_TOKEN_EXPIRE_SECONDS``.

It is important that this command is run regularly (eg: via cron) to avoid cluttering the
database with expired refresh tokens.

If ``cleartokens`` runs daily the maximum delay before a refresh token is
removed is its retention period (``REFRESH_TOKEN_EXPIRE_SECONDS`` for expired
tokens, ``REFRESH_TOKEN_GRACE_PERIOD_SECONDS`` for revoked ones) + 1 day. This
is normally not a problem since refresh tokens are long lived.

Note that ``REFRESH_TOKEN_EXPIRE_SECONDS`` is also enforced when a refresh token is presented, so a
refresh token past its lifetime is rejected even if ``cleartokens`` has not yet removed it.

To prevent the CPU and RAM high peaks during deletion process use ``CLEAR_EXPIRED_TOKENS_BATCH_SIZE`` and
``CLEAR_EXPIRED_TOKENS_BATCH_INTERVAL`` settings to adjust the process speed.

The ``cleartokens`` management command will also delete expired access and ID tokens alongside expired refresh tokens.

Refresh tokens that have already been revoked (for example by refresh token rotation) are removed as
soon as their ``REFRESH_TOKEN_GRACE_PERIOD_SECONDS`` grace period has passed, without waiting for
``REFRESH_TOKEN_EXPIRE_SECONDS``. The exception is when ``REFRESH_TOKEN_REUSE_PROTECTION`` is enabled:
revoked refresh tokens are then what allows reuse of a rotated token to be detected, so they are kept
until they expire per ``REFRESH_TOKEN_EXPIRE_SECONDS``.

Note: Refresh tokens need to expire before AccessTokens can be removed from the
database. Using ``cleartokens`` without ``REFRESH_TOKEN_EXPIRE_SECONDS`` has limited effect.
When ``REFRESH_TOKEN_EXPIRE_SECONDS`` is unset (or ``0``), ``cleartokens`` prints a warning to
stderr to make this easy to notice: only revoked and orphaned refresh tokens are removed, and
expired access and ID tokens that are still bound to a refresh token are retained as long as that
refresh token lives. (Expired access tokens with no refresh token, and their ID tokens, are still
cleared regardless of ``REFRESH_TOKEN_EXPIRE_SECONDS``.) Set ``REFRESH_TOKEN_EXPIRE_SECONDS`` to
enable expiry-based cleanup.

.. _clearcimdapplications:

clearcimdapplications
~~~~~~~~~~~~~~~~~~~~~

The ``clearcimdapplications`` management command deletes :doc:`CIMD-registered <cimd>` applications
(``registration_source="cimd"``) whose cached metadata has expired (``cimd_expires_at`` in the past)
and that hold no live access token, ID token, grant, or unrevoked refresh token. Because CIMD rows
are created automatically on first sight of a client URL — and re-created the same way if the client
returns — deleting them only reclaims storage. Run it regularly (eg: via cron, alongside
``cleartokens``) when CIMD is enabled, since the application store is otherwise attacker-mintable
(see :ref:`the CIMD security model <cimd-security>`).

Deletion is batched (``--batch-size``, default 1000). Each batch's liveness check and delete run in
one transaction with the application rows locked, so a token minted concurrently cannot slip in
between the check and the delete and be cascade-deleted with its application; batching keeps the
number of rows locked at once bounded.

.. _createapplication:

createapplication
~~~~~~~~~~~~~~~~~

The ``createapplication`` management command provides a shortcut to create a new application in a programmatic way.

.. code-block:: text

    usage: manage.py createapplication [-h] [--client-id CLIENT_ID] [--user USER]
                                       [--redirect-uris REDIRECT_URIS]
                                       [--post-logout-redirect-uris POST_LOGOUT_REDIRECT_URIS]
                                       [--client-secret CLIENT_SECRET]
                                       [--name NAME] [--skip-authorization]
                                       [--algorithm ALGORITHM] [--version]
                                       [-v {0,1,2,3}] [--settings SETTINGS]
                                       [--pythonpath PYTHONPATH] [--traceback]
                                       [--no-color] [--force-color]
                                       [--skip-checks]
                                       client_type authorization_grant_type

    Shortcut to create a new application in a programmatic way

    positional arguments:
      client_type           The client type, one of: confidential, public
      authorization_grant_type
                            The type of authorization grant to be used, one of:
                            authorization-code, implicit, password, client-
                            credentials, openid-hybrid

    optional arguments:
      -h, --help            show this help message and exit
      --client-id CLIENT_ID
                            The ID of the new application
      --user USER           The user the application belongs to
      --redirect-uris REDIRECT_URIS
                            The redirect URIs, this must be a space separated
                            string e.g 'URI1 URI2'
      --post-logout-redirect-uris POST_LOGOUT_REDIRECT_URIS
                            The post logout redirect URIs, this must be a space
                            separated string e.g 'URI1 URI2'
      --client-secret CLIENT_SECRET
                            The secret for this application
      --name NAME           The name this application
      --skip-authorization  If set, completely bypass the authorization form, even
                            on the first use of the application
      --algorithm ALGORITHM
                            The OIDC token signing algorithm for this application,
                            one of: RS256, HS256
      --version             Show program's version number and exit.
      -v {0,1,2,3}, --verbosity {0,1,2,3}
                            Verbosity level; 0=minimal output, 1=normal output,
                            2=verbose output, 3=very verbose output
      --settings SETTINGS   The Python path to a settings module, e.g.
                            "myproject.settings.main". If this isn't provided, the
                            DJANGO_SETTINGS_MODULE environment variable will be
                            used.
      --pythonpath PYTHONPATH
                            A directory to add to the Python path, e.g.
                            "/home/djangoprojects/myproject".
      --traceback           Raise on CommandError exceptions.
      --no-color            Don't colorize the command output.
      --force-color         Force colorization of the command output.
      --skip-checks         Skip system checks.

If you let ``createapplication`` auto-generate the secret then it displays the value before hashing it.
