1 # -*- coding: utf-8 -*-
3 oauthlib.oauth2.rfc6749.grant_types
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 from __future__ import unicode_literals, absolute_import
11 from .base import GrantTypeBase
12 from .. import errors, utils
13 from ..request_validator import RequestValidator
15 log = logging.getLogger(__name__)
18 class RefreshTokenGrant(GrantTypeBase):
20 """`Refresh token grant`_
22 .. _`Refresh token grant`: http://tools.ietf.org/html/rfc6749#section-6
26 def issue_new_refresh_tokens(self):
29 def __init__(self, request_validator=None, issue_new_refresh_tokens=True):
30 self.request_validator = request_validator or RequestValidator()
32 def create_token_response(self, request, token_handler):
33 """Create a new access token from a refresh_token.
35 If valid and authorized, the authorization server issues an access
36 token as described in `Section 5.1`_. If the request failed
37 verification or is invalid, the authorization server returns an error
38 response as described in `Section 5.2`_.
40 The authorization server MAY issue a new refresh token, in which case
41 the client MUST discard the old refresh token and replace it with the
42 new refresh token. The authorization server MAY revoke the old
43 refresh token after issuing a new refresh token to the client. If a
44 new refresh token is issued, the refresh token scope MUST be
45 identical to that of the refresh token included by the client in the
48 .. _`Section 5.1`: http://tools.ietf.org/html/rfc6749#section-5.1
49 .. _`Section 5.2`: http://tools.ietf.org/html/rfc6749#section-5.2
52 'Content-Type': 'application/json',
53 'Cache-Control': 'no-store',
57 log.debug('Validating refresh token request, %r.', request)
58 self.validate_token_request(request)
59 except errors.OAuth2Error as e:
60 return headers, e.json, e.status_code
62 token = token_handler.create_token(request,
63 refresh_token=self.issue_new_refresh_tokens)
64 log.debug('Issuing new token to client id %r (%r), %r.',
65 request.client_id, request.client, token)
66 return headers, json.dumps(token), 200
68 def validate_token_request(self, request):
69 # REQUIRED. Value MUST be set to "refresh_token".
70 if request.grant_type != 'refresh_token':
71 raise errors.UnsupportedGrantTypeError(request=request)
73 if request.refresh_token is None:
74 raise errors.InvalidRequestError(
75 description='Missing refresh token parameter.',
78 # Because refresh tokens are typically long-lasting credentials used to
79 # request additional access tokens, the refresh token is bound to the
80 # client to which it was issued. If the client type is confidential or
81 # the client was issued client credentials (or assigned other
82 # authentication requirements), the client MUST authenticate with the
83 # authorization server as described in Section 3.2.1.
84 # http://tools.ietf.org/html/rfc6749#section-3.2.1
85 if self.request_validator.client_authentication_required(request):
86 log.debug('Authenticating client, %r.', request)
87 if not self.request_validator.authenticate_client(request):
88 log.debug('Invalid client (%r), denying access.', request)
89 raise errors.InvalidClientError(request=request)
90 elif not self.request_validator.authenticate_client_id(request.client_id, request):
91 log.debug('Client authentication failed, %r.', request)
92 raise errors.InvalidClientError(request=request)
94 # Ensure client is authorized use of this grant type
95 self.validate_grant_type(request)
97 # REQUIRED. The refresh token issued to the client.
98 log.debug('Validating refresh token %s for client %r.',
99 request.refresh_token, request.client)
100 if not self.request_validator.validate_refresh_token(
101 request.refresh_token, request.client, request):
102 log.debug('Invalid refresh token, %s, for client %r.',
103 request.refresh_token, request.client)
104 raise errors.InvalidGrantError(request=request)
106 original_scopes = utils.scope_to_list(
107 self.request_validator.get_original_scopes(
108 request.refresh_token, request))
111 request.scopes = utils.scope_to_list(request.scope)
112 if (not all((s in original_scopes for s in request.scopes))
113 and not self.request_validator.is_within_original_scope(
114 request.scopes, request.refresh_token, request)):
115 log.debug('Refresh token %s lack requested scopes, %r.',
116 request.refresh_token, request.scopes)
117 raise errors.InvalidScopeError(request=request)
119 request.scopes = original_scopes