1"""
2oauthlib.oauth2.rfc6749.grant_types
3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4"""
5import json
6import logging
7
8from .. import errors, utils
9from .base import GrantTypeBase
10
11log = logging.getLogger(__name__)
12
13
14class RefreshTokenGrant(GrantTypeBase):
15
16 """`Refresh token grant`_
17
18 .. _`Refresh token grant`: https://tools.ietf.org/html/rfc6749#section-6
19 """
20
21 def __init__(self, request_validator=None,
22 issue_new_refresh_tokens=True,
23 **kwargs):
24 super().__init__(
25 request_validator,
26 issue_new_refresh_tokens=issue_new_refresh_tokens,
27 **kwargs)
28
29 def create_token_response(self, request, token_handler):
30 """Create a new access token from a refresh_token.
31
32 :param request: OAuthlib request.
33 :type request: oauthlib.common.Request
34 :param token_handler: A token handler instance, for example of type
35 oauthlib.oauth2.BearerToken.
36
37 If valid and authorized, the authorization server issues an access
38 token as described in `Section 5.1`_. If the request failed
39 verification or is invalid, the authorization server returns an error
40 response as described in `Section 5.2`_.
41
42 The authorization server MAY issue a new refresh token, in which case
43 the client MUST discard the old refresh token and replace it with the
44 new refresh token. The authorization server MAY revoke the old
45 refresh token after issuing a new refresh token to the client. If a
46 new refresh token is issued, the refresh token scope MUST be
47 identical to that of the refresh token included by the client in the
48 request.
49
50 .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1
51 .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2
52 """
53 headers = self._get_default_headers()
54 try:
55 log.debug('Validating refresh token request, %r.', request)
56 self.validate_token_request(request)
57 except errors.OAuth2Error as e:
58 log.debug('Client error in token request, %s.', e)
59 headers.update(e.headers)
60 return headers, e.json, e.status_code
61
62 token = token_handler.create_token(request,
63 refresh_token=self.issue_new_refresh_tokens)
64
65 for modifier in self._token_modifiers:
66 token = modifier(token, token_handler, request)
67
68 self.request_validator.save_token(token, request)
69
70 log.debug('Issuing new token to client id %r (%r), %r.',
71 request.client_id, request.client, token)
72 headers.update(self._create_cors_headers(request))
73 return headers, json.dumps(token), 200
74
75 def validate_token_request(self, request):
76 """
77 :param request: OAuthlib request.
78 :type request: oauthlib.common.Request
79 """
80 # REQUIRED. Value MUST be set to "refresh_token".
81 if request.grant_type != 'refresh_token':
82 raise errors.UnsupportedGrantTypeError(request=request)
83
84 for validator in self.custom_validators.pre_token:
85 validator(request)
86
87 if request.refresh_token is None:
88 raise errors.InvalidRequestError(
89 description='Missing refresh token parameter.',
90 request=request)
91
92 # Because refresh tokens are typically long-lasting credentials used to
93 # request additional access tokens, the refresh token is bound to the
94 # client to which it was issued. If the client type is confidential or
95 # the client was issued client credentials (or assigned other
96 # authentication requirements), the client MUST authenticate with the
97 # authorization server as described in Section 3.2.1.
98 # https://tools.ietf.org/html/rfc6749#section-3.2.1
99 if self.request_validator.client_authentication_required(request):
100 log.debug('Authenticating client, %r.', request)
101 if not self.request_validator.authenticate_client(request):
102 log.debug('Invalid client (%r), denying access.', request)
103 raise errors.InvalidClientError(request=request)
104 # Ensure that request.client_id is set.
105 if request.client_id is None and request.client is not None:
106 request.client_id = request.client.client_id
107 elif not self.request_validator.authenticate_client_id(request.client_id, request):
108 log.debug('Client authentication failed, %r.', request)
109 raise errors.InvalidClientError(request=request)
110
111 # Ensure client is authorized use of this grant type
112 self.validate_grant_type(request)
113
114 # REQUIRED. The refresh token issued to the client.
115 log.debug('Validating refresh token %s for client %r.',
116 request.refresh_token, request.client)
117 if not self.request_validator.validate_refresh_token(
118 request.refresh_token, request.client, request):
119 log.debug('Invalid refresh token, %s, for client %r.',
120 request.refresh_token, request.client)
121 raise errors.InvalidGrantError(request=request)
122
123 original_scopes = utils.scope_to_list(
124 self.request_validator.get_original_scopes(
125 request.refresh_token, request))
126
127 if request.scope:
128 request.scopes = utils.scope_to_list(request.scope)
129 if (not all(s in original_scopes for s in request.scopes)
130 and not self.request_validator.is_within_original_scope(
131 request.scopes, request.refresh_token, request)):
132 log.debug('Refresh token %s lack requested scopes, %r.',
133 request.refresh_token, request.scopes)
134 raise errors.InvalidScopeError(request=request)
135 else:
136 request.scopes = original_scopes
137
138 for validator in self.custom_validators.post_token:
139 validator(request)