1"""
2oauthlib.oauth2.rfc6749.grant_types
3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4"""
5import json
6import logging
7
8from .. import errors
9from .base import GrantTypeBase
10
11log = logging.getLogger(__name__)
12
13
14class ClientCredentialsGrant(GrantTypeBase):
15
16 """`Client Credentials Grant`_
17
18 The client can request an access token using only its client
19 credentials (or other supported means of authentication) when the
20 client is requesting access to the protected resources under its
21 control, or those of another resource owner that have been previously
22 arranged with the authorization server (the method of which is beyond
23 the scope of this specification).
24
25 The client credentials grant type MUST only be used by confidential
26 clients::
27
28 +---------+ +---------------+
29 : : : :
30 : :>-- A - Client Authentication --->: Authorization :
31 : Client : : Server :
32 : :<-- B ---- Access Token ---------<: :
33 : : : :
34 +---------+ +---------------+
35
36 Figure 6: Client Credentials Flow
37
38 The flow illustrated in Figure 6 includes the following steps:
39
40 (A) The client authenticates with the authorization server and
41 requests an access token from the token endpoint.
42
43 (B) The authorization server authenticates the client, and if valid,
44 issues an access token.
45
46 .. _`Client Credentials Grant`: https://tools.ietf.org/html/rfc6749#section-4.4
47 """
48
49 def create_token_response(self, request, token_handler):
50 """Return token or error in JSON format.
51
52 :param request: OAuthlib request.
53 :type request: oauthlib.common.Request
54 :param token_handler: A token handler instance, for example of type
55 oauthlib.oauth2.BearerToken.
56
57 If the access token request is valid and authorized, the
58 authorization server issues an access token as described in
59 `Section 5.1`_. A refresh token SHOULD NOT be included. If the request
60 failed client authentication or is invalid, the authorization server
61 returns an error response as described in `Section 5.2`_.
62
63 .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1
64 .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2
65 """
66 headers = self._get_default_headers()
67 try:
68 log.debug('Validating access token request, %r.', request)
69 self.validate_token_request(request)
70 except errors.OAuth2Error as e:
71 log.debug('Client error in token request. %s.', e)
72 headers.update(e.headers)
73 return headers, e.json, e.status_code
74
75 token = token_handler.create_token(request, refresh_token=False)
76
77 for modifier in self._token_modifiers:
78 token = modifier(token)
79
80 self.request_validator.save_token(token, request)
81
82 log.debug('Issuing token to client id %r (%r), %r.',
83 request.client_id, request.client, token)
84 return headers, json.dumps(token), 200
85
86 def validate_token_request(self, request):
87 """
88 :param request: OAuthlib request.
89 :type request: oauthlib.common.Request
90 """
91 for validator in self.custom_validators.pre_token:
92 validator(request)
93
94 if not getattr(request, 'grant_type', None):
95 raise errors.InvalidRequestError('Request is missing grant type.',
96 request=request)
97
98 if not request.grant_type == 'client_credentials':
99 raise errors.UnsupportedGrantTypeError(request=request)
100
101 for param in ('grant_type', 'scope'):
102 if param in request.duplicate_params:
103 raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param,
104 request=request)
105
106 log.debug('Authenticating client, %r.', request)
107 if not self.request_validator.authenticate_client(request):
108 log.debug('Client authentication failed, %r.', request)
109 raise errors.InvalidClientError(request=request)
110 elif not hasattr(request.client, 'client_id'):
111 raise NotImplementedError('Authenticate client must set the '
112 'request.client.client_id attribute '
113 'in authenticate_client.')
114 # Ensure client is authorized use of this grant type
115 self.validate_grant_type(request)
116
117 request.client_id = request.client_id or request.client.client_id
118 log.debug('Authorizing access to client %r.', request.client_id)
119 self.validate_scopes(request)
120
121 for validator in self.custom_validators.post_token:
122 validator(request)