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 @@ -22,3 +22,4 @@ Jim Graham
pySilver
Silvano Cerza
Federico Dolce
Alessandro De Angelis
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Changelog
Development
~~~~~~~~~~~

* #424: Added a ROTATE_REFRESH_TOKEN setting to control whether refresh tokens are reused or not
* #315: AuthorizationView does not overwrite requests on get
* #425: Added support for Django 1.10
* #396: Added an IsAuthenticatedOrTokenHasScope Permission
Expand Down
5 changes: 4 additions & 1 deletion docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,11 @@ REFRESH_TOKEN_EXPIRE_SECONDS
The number of seconds before a refresh token gets removed from the database by
the ``cleartokens`` management command. Check :ref:`cleartokens` management command for further info.

ROTATE_REFRESH_TOKEN
~~~~~~~~~~~~~~~~~~~~
When is set to `True` (default) a new refresh token is issued to the client when the client refreshes an access token.

REQUEST_APPROVAL_PROMPT
~~~~~~~~~~~~~~~~~~~~~~~
Can be ``'force'`` or ``'auto'``.
The strategy used to display the authorization form. Refer to :ref:`skip-auth-form`.

6 changes: 6 additions & 0 deletions oauth2_provider/oauth2_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,12 @@ def save_authorization_code(self, client_id, code, request, *args, **kwargs):
scope=' '.join(request.scopes))
g.save()

def rotate_refresh_token(self, request):
"""
Checks if rotate refresh token is enabled
"""
return oauth2_settings.ROTATE_REFRESH_TOKEN

@transaction.atomic
def save_bearer_token(self, token, request, *args, **kwargs):
"""
Expand Down
1 change: 1 addition & 0 deletions oauth2_provider/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
'AUTHORIZATION_CODE_EXPIRE_SECONDS': 60,
'ACCESS_TOKEN_EXPIRE_SECONDS': 36000,
'REFRESH_TOKEN_EXPIRE_SECONDS': None,
'ROTATE_REFRESH_TOKEN': True,
'APPLICATION_MODEL': getattr(settings, 'OAUTH2_PROVIDER_APPLICATION_MODEL', 'oauth2_provider.Application'),
'REQUEST_APPROVAL_PROMPT': 'force',
'ALLOWED_REDIRECT_URI_SCHEMES': ['http', 'https'],
Expand Down
14 changes: 7 additions & 7 deletions oauth2_provider/tests/test_authorization_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import base64
import json
import datetime
import mock

from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
Expand Down Expand Up @@ -707,13 +706,14 @@ def test_refresh_repeating_requests_non_rotating_tokens(self):
'refresh_token': content['refresh_token'],
'scope': content['scope'],
}
oauth2_settings.ROTATE_REFRESH_TOKEN = False

with mock.patch('oauthlib.oauth2.rfc6749.request_validator.RequestValidator.rotate_refresh_token',
return_value=False):
response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers)
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers)
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers)
self.assertEqual(response.status_code, 200)
response = self.client.post(reverse('oauth2_provider:token'), data=token_request_data, **auth_headers)
self.assertEqual(response.status_code, 200)

oauth2_settings.ROTATE_REFRESH_TOKEN = True

def test_basic_auth_bad_authcode(self):
"""
Expand Down