Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ David Fischer
Ash Christopher
Rodney Richardson
Hiroki Kiyohara
Bas van Oostveen
13 changes: 13 additions & 0 deletions docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ READ_SCOPE
~~~~~~~~~~
The name of the *read* scope.

REFRESH_TOKEN_EXPIRE_SECONDS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The number of seconds before a refresh token gets removed from the database by
the ``cleartokens``` management command. It's important that ``cleartokens``
runs regularly (eg: via cron) in order for this setting to work.

If ``cleartokens`` runs daily the maximum delay before a refresh token is
removed is ``REFRESH_TOKEN_EXPIRE_SECONDS`` + 1 day. This is normally not a
problem since refresh tokens are long lived.

Note: Refresh tokens need to expire before AccessTokens can be removed from the
database. Using ``cleartokens`` without ``REFRESH_TOKEN_EXPIRE_SECONDS`` has limited effect.

WRITE_SCOPE
~~~~~~~~~~~
The name of the *write* scope.
Expand Down
Empty file.
Empty file.
9 changes: 9 additions & 0 deletions oauth2_provider/management/commands/cleartokens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.core.management.base import BaseCommand, CommandError
from ...models import clear_expired


class Command(BaseCommand):
help = "Can be run as a cronjob or directly to clean out expired tokens"

def handle(self, *args, **options):
clear_expired()
25 changes: 24 additions & 1 deletion oauth2_provider/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import unicode_literals

from datetime import timedelta

from django.core.urlresolvers import reverse
from django.db import models
from django.db import models, transaction
from django.utils import timezone

from django.utils.translation import ugettext_lazy as _
Expand Down Expand Up @@ -253,3 +255,24 @@ def get_application_model():
e = "APPLICATION_MODEL refers to model {0} that has not been installed"
raise ImproperlyConfigured(e.format(oauth2_settings.APPLICATION_MODEL))
return app_model


def clear_expired():
now = timezone.now()
refresh_expire_at = None

REFRESH_TOKEN_EXPIRE_SECONDS = oauth2_settings.REFRESH_TOKEN_EXPIRE_SECONDS
if REFRESH_TOKEN_EXPIRE_SECONDS:
if not isinstance(REFRESH_TOKEN_EXPIRE_SECONDS, timedelta):
try:
REFRESH_TOKEN_EXPIRE_SECONDS = timedelta(seconds=REFRESH_TOKEN_EXPIRE_SECONDS)
except TypeError:
e = "REFRESH_TOKEN_EXPIRE_SECONDS must be either a timedelta or seconds"
raise ImproperlyConfigured(e)
refresh_expire_at = now - REFRESH_TOKEN_EXPIRE_SECONDS

with transaction.atomic():
if refresh_expire_at:
RefreshToken.objects.filter(access_token__expires__lt=refresh_expire_at).delete()
AccessToken.objects.filter(refresh_token__isnull=True, expires__lt=now).delete()
Grant.objects.filter(expires__lt=now).delete()
1 change: 1 addition & 0 deletions oauth2_provider/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
'WRITE_SCOPE': 'write',
'AUTHORIZATION_CODE_EXPIRE_SECONDS': 60,
'ACCESS_TOKEN_EXPIRE_SECONDS': 36000,
'REFRESH_TOKEN_EXPIRE_SECONDS': None,
'APPLICATION_MODEL': getattr(settings, 'OAUTH2_PROVIDER_APPLICATION_MODEL', 'oauth2_provider.Application'),
'REQUEST_APPROVAL_PROMPT': 'force',
'ALLOWED_REDIRECT_URI_SCHEMES': ['http', 'https'],
Expand Down