1"""
2oauthlib.oauth2.rfc6749
3~~~~~~~~~~~~~~~~~~~~~~~
4
5This module is an implementation of various logic needed
6for consuming and providing OAuth 2.0 RFC6749.
7"""
8import logging
9
10from oauthlib.common import Request
11from oauthlib.oauth2.rfc6749 import utils
12
13from .base import BaseEndpoint, catch_errors_and_unavailability
14
15log = logging.getLogger(__name__)
16
17
18class TokenEndpoint(BaseEndpoint):
19
20 """Token issuing endpoint.
21
22 The token endpoint is used by the client to obtain an access token by
23 presenting its authorization grant or refresh token. The token
24 endpoint is used with every authorization grant except for the
25 implicit grant type (since an access token is issued directly).
26
27 The means through which the client obtains the location of the token
28 endpoint are beyond the scope of this specification, but the location
29 is typically provided in the service documentation.
30
31 The endpoint URI MAY include an "application/x-www-form-urlencoded"
32 formatted (per `Appendix B`_) query component,
33 which MUST be retained when adding additional query parameters. The
34 endpoint URI MUST NOT include a fragment component::
35
36 https://example.com/path?query=component # OK
37 https://example.com/path?query=component#fragment # Not OK
38
39 Since requests to the token endpoint result in the transmission of
40 clear-text credentials (in the HTTP request and response), the
41 authorization server MUST require the use of TLS as described in
42 Section 1.6 when sending requests to the token endpoint::
43
44 # We will deny any request which URI schema is not with https
45
46 The client MUST use the HTTP "POST" method when making access token
47 requests::
48
49 # HTTP method is currently not enforced
50
51 Parameters sent without a value MUST be treated as if they were
52 omitted from the request. The authorization server MUST ignore
53 unrecognized request parameters. Request and response parameters
54 MUST NOT be included more than once::
55
56 # Delegated to each grant type.
57
58 .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
59 """
60
61 valid_request_methods = ('POST',)
62
63 def __init__(self, default_grant_type, default_token_type, grant_types):
64 BaseEndpoint.__init__(self)
65 self._grant_types = grant_types
66 self._default_token_type = default_token_type
67 self._default_grant_type = default_grant_type
68
69 @property
70 def grant_types(self):
71 return self._grant_types
72
73 @property
74 def default_grant_type(self):
75 return self._default_grant_type
76
77 @property
78 def default_grant_type_handler(self):
79 return self.grant_types.get(self.default_grant_type)
80
81 @property
82 def default_token_type(self):
83 return self._default_token_type
84
85 @catch_errors_and_unavailability
86 def create_token_response(self, uri, http_method='POST', body=None,
87 headers=None, credentials=None, grant_type_for_scope=None,
88 claims=None):
89 """Extract grant_type and route to the designated handler."""
90 request = Request(
91 uri, http_method=http_method, body=body, headers=headers)
92 self.validate_token_request(request)
93 # 'scope' is an allowed Token Request param in both the "Resource Owner Password Credentials Grant"
94 # and "Client Credentials Grant" flows
95 # https://tools.ietf.org/html/rfc6749#section-4.3.2
96 # https://tools.ietf.org/html/rfc6749#section-4.4.2
97 request.scopes = utils.scope_to_list(request.scope)
98
99 request.extra_credentials = credentials
100 if grant_type_for_scope:
101 request.grant_type = grant_type_for_scope
102
103 # OpenID Connect claims, if provided. The server using oauthlib might choose
104 # to implement the claims parameter of the Authorization Request. In this case
105 # it should retrieve those claims and pass them via the claims argument here,
106 # as a dict.
107 if claims:
108 request.claims = claims
109
110 grant_type_handler = self.grant_types.get(request.grant_type,
111 self.default_grant_type_handler)
112 log.debug('Dispatching grant_type %s request to %r.',
113 request.grant_type, grant_type_handler)
114 return grant_type_handler.create_token_response(
115 request, self.default_token_type)
116
117 def validate_token_request(self, request):
118 self._raise_on_bad_method(request)
119 self._raise_on_bad_post_request(request)