Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/grant_types/implicit.py: 20%
64 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:22 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:22 +0000
1"""
2oauthlib.oauth2.rfc6749.grant_types
3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4"""
5import logging
7from oauthlib import common
9from .. import errors
10from .base import GrantTypeBase
12log = logging.getLogger(__name__)
15class ImplicitGrant(GrantTypeBase):
17 """`Implicit Grant`_
19 The implicit grant type is used to obtain access tokens (it does not
20 support the issuance of refresh tokens) and is optimized for public
21 clients known to operate a particular redirection URI. These clients
22 are typically implemented in a browser using a scripting language
23 such as JavaScript.
25 Unlike the authorization code grant type, in which the client makes
26 separate requests for authorization and for an access token, the
27 client receives the access token as the result of the authorization
28 request.
30 The implicit grant type does not include client authentication, and
31 relies on the presence of the resource owner and the registration of
32 the redirection URI. Because the access token is encoded into the
33 redirection URI, it may be exposed to the resource owner and other
34 applications residing on the same device::
36 +----------+
37 | Resource |
38 | Owner |
39 | |
40 +----------+
41 ^
42 |
43 (B)
44 +----|-----+ Client Identifier +---------------+
45 | -+----(A)-- & Redirection URI --->| |
46 | User- | | Authorization |
47 | Agent -|----(B)-- User authenticates -->| Server |
48 | | | |
49 | |<---(C)--- Redirection URI ----<| |
50 | | with Access Token +---------------+
51 | | in Fragment
52 | | +---------------+
53 | |----(D)--- Redirection URI ---->| Web-Hosted |
54 | | without Fragment | Client |
55 | | | Resource |
56 | (F) |<---(E)------- Script ---------<| |
57 | | +---------------+
58 +-|--------+
59 | |
60 (A) (G) Access Token
61 | |
62 ^ v
63 +---------+
64 | |
65 | Client |
66 | |
67 +---------+
69 Note: The lines illustrating steps (A) and (B) are broken into two
70 parts as they pass through the user-agent.
72 Figure 4: Implicit Grant Flow
74 The flow illustrated in Figure 4 includes the following steps:
76 (A) The client initiates the flow by directing the resource owner's
77 user-agent to the authorization endpoint. The client includes
78 its client identifier, requested scope, local state, and a
79 redirection URI to which the authorization server will send the
80 user-agent back once access is granted (or denied).
82 (B) The authorization server authenticates the resource owner (via
83 the user-agent) and establishes whether the resource owner
84 grants or denies the client's access request.
86 (C) Assuming the resource owner grants access, the authorization
87 server redirects the user-agent back to the client using the
88 redirection URI provided earlier. The redirection URI includes
89 the access token in the URI fragment.
91 (D) The user-agent follows the redirection instructions by making a
92 request to the web-hosted client resource (which does not
93 include the fragment per [RFC2616]). The user-agent retains the
94 fragment information locally.
96 (E) The web-hosted client resource returns a web page (typically an
97 HTML document with an embedded script) capable of accessing the
98 full redirection URI including the fragment retained by the
99 user-agent, and extracting the access token (and other
100 parameters) contained in the fragment.
102 (F) The user-agent executes the script provided by the web-hosted
103 client resource locally, which extracts the access token.
105 (G) The user-agent passes the access token to the client.
107 See `Section 10.3`_ and `Section 10.16`_ for important security considerations
108 when using the implicit grant.
110 .. _`Implicit Grant`: https://tools.ietf.org/html/rfc6749#section-4.2
111 .. _`Section 10.3`: https://tools.ietf.org/html/rfc6749#section-10.3
112 .. _`Section 10.16`: https://tools.ietf.org/html/rfc6749#section-10.16
113 """
115 response_types = ['token']
116 grant_allows_refresh_token = False
118 def create_authorization_response(self, request, token_handler):
119 """Create an authorization response.
121 :param request: OAuthlib request.
122 :type request: oauthlib.common.Request
123 :param token_handler: A token handler instance, for example of type
124 oauthlib.oauth2.BearerToken.
126 The client constructs the request URI by adding the following
127 parameters to the query component of the authorization endpoint URI
128 using the "application/x-www-form-urlencoded" format, per `Appendix B`_:
130 response_type
131 REQUIRED. Value MUST be set to "token" for standard OAuth2 implicit flow
132 or "id_token token" or just "id_token" for OIDC implicit flow
134 client_id
135 REQUIRED. The client identifier as described in `Section 2.2`_.
137 redirect_uri
138 OPTIONAL. As described in `Section 3.1.2`_.
140 scope
141 OPTIONAL. The scope of the access request as described by
142 `Section 3.3`_.
144 state
145 RECOMMENDED. An opaque value used by the client to maintain
146 state between the request and callback. The authorization
147 server includes this value when redirecting the user-agent back
148 to the client. The parameter SHOULD be used for preventing
149 cross-site request forgery as described in `Section 10.12`_.
151 The authorization server validates the request to ensure that all
152 required parameters are present and valid. The authorization server
153 MUST verify that the redirection URI to which it will redirect the
154 access token matches a redirection URI registered by the client as
155 described in `Section 3.1.2`_.
157 .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2
158 .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2
159 .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
160 .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
161 .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
162 """
163 return self.create_token_response(request, token_handler)
165 def create_token_response(self, request, token_handler):
166 """Return token or error embedded in the URI fragment.
168 :param request: OAuthlib request.
169 :type request: oauthlib.common.Request
170 :param token_handler: A token handler instance, for example of type
171 oauthlib.oauth2.BearerToken.
173 If the resource owner grants the access request, the authorization
174 server issues an access token and delivers it to the client by adding
175 the following parameters to the fragment component of the redirection
176 URI using the "application/x-www-form-urlencoded" format, per
177 `Appendix B`_:
179 access_token
180 REQUIRED. The access token issued by the authorization server.
182 token_type
183 REQUIRED. The type of the token issued as described in
184 `Section 7.1`_. Value is case insensitive.
186 expires_in
187 RECOMMENDED. The lifetime in seconds of the access token. For
188 example, the value "3600" denotes that the access token will
189 expire in one hour from the time the response was generated.
190 If omitted, the authorization server SHOULD provide the
191 expiration time via other means or document the default value.
193 scope
194 OPTIONAL, if identical to the scope requested by the client;
195 otherwise, REQUIRED. The scope of the access token as
196 described by `Section 3.3`_.
198 state
199 REQUIRED if the "state" parameter was present in the client
200 authorization request. The exact value received from the
201 client.
203 The authorization server MUST NOT issue a refresh token.
205 .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
206 .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
207 .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1
208 """
209 try:
210 self.validate_token_request(request)
212 # If the request fails due to a missing, invalid, or mismatching
213 # redirection URI, or if the client identifier is missing or invalid,
214 # the authorization server SHOULD inform the resource owner of the
215 # error and MUST NOT automatically redirect the user-agent to the
216 # invalid redirection URI.
217 except errors.FatalClientError as e:
218 log.debug('Fatal client error during validation of %r. %r.',
219 request, e)
220 raise
222 # If the resource owner denies the access request or if the request
223 # fails for reasons other than a missing or invalid redirection URI,
224 # the authorization server informs the client by adding the following
225 # parameters to the fragment component of the redirection URI using the
226 # "application/x-www-form-urlencoded" format, per Appendix B:
227 # https://tools.ietf.org/html/rfc6749#appendix-B
228 except errors.OAuth2Error as e:
229 log.debug('Client error during validation of %r. %r.', request, e)
230 return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples,
231 fragment=True)}, None, 302
233 # In OIDC implicit flow it is possible to have a request_type that does not include the access_token!
234 # "id_token token" - return the access token and the id token
235 # "id_token" - don't return the access token
236 if "token" in request.response_type.split():
237 token = token_handler.create_token(request, refresh_token=False)
238 else:
239 token = {}
241 if request.state is not None:
242 token['state'] = request.state
244 for modifier in self._token_modifiers:
245 token = modifier(token, token_handler, request)
247 # In OIDC implicit flow it is possible to have a request_type that does
248 # not include the access_token! In this case there is no need to save a token.
249 if "token" in request.response_type.split():
250 self.request_validator.save_token(token, request)
252 return self.prepare_authorization_response(
253 request, token, {}, None, 302)
255 def validate_authorization_request(self, request):
256 """
257 :param request: OAuthlib request.
258 :type request: oauthlib.common.Request
259 """
260 return self.validate_token_request(request)
262 def validate_token_request(self, request):
263 """Check the token request for normal and fatal errors.
265 :param request: OAuthlib request.
266 :type request: oauthlib.common.Request
268 This method is very similar to validate_authorization_request in
269 the AuthorizationCodeGrant but differ in a few subtle areas.
271 A normal error could be a missing response_type parameter or the client
272 attempting to access scope it is not allowed to ask authorization for.
273 Normal errors can safely be included in the redirection URI and
274 sent back to the client.
276 Fatal errors occur when the client_id or redirect_uri is invalid or
277 missing. These must be caught by the provider and handled, how this
278 is done is outside of the scope of OAuthLib but showing an error
279 page describing the issue is a good idea.
280 """
282 # First check for fatal errors
284 # If the request fails due to a missing, invalid, or mismatching
285 # redirection URI, or if the client identifier is missing or invalid,
286 # the authorization server SHOULD inform the resource owner of the
287 # error and MUST NOT automatically redirect the user-agent to the
288 # invalid redirection URI.
290 # First check duplicate parameters
291 for param in ('client_id', 'response_type', 'redirect_uri', 'scope', 'state'):
292 try:
293 duplicate_params = request.duplicate_params
294 except ValueError:
295 raise errors.InvalidRequestFatalError(description='Unable to parse query string', request=request)
296 if param in duplicate_params:
297 raise errors.InvalidRequestFatalError(description='Duplicate %s parameter.' % param, request=request)
299 # REQUIRED. The client identifier as described in Section 2.2.
300 # https://tools.ietf.org/html/rfc6749#section-2.2
301 if not request.client_id:
302 raise errors.MissingClientIdError(request=request)
304 if not self.request_validator.validate_client_id(request.client_id, request):
305 raise errors.InvalidClientIdError(request=request)
307 # OPTIONAL. As described in Section 3.1.2.
308 # https://tools.ietf.org/html/rfc6749#section-3.1.2
309 self._handle_redirects(request)
311 # Then check for normal errors.
313 request_info = self._run_custom_validators(request,
314 self.custom_validators.all_pre)
316 # If the resource owner denies the access request or if the request
317 # fails for reasons other than a missing or invalid redirection URI,
318 # the authorization server informs the client by adding the following
319 # parameters to the fragment component of the redirection URI using the
320 # "application/x-www-form-urlencoded" format, per Appendix B.
321 # https://tools.ietf.org/html/rfc6749#appendix-B
323 # Note that the correct parameters to be added are automatically
324 # populated through the use of specific exceptions
326 # REQUIRED.
327 if request.response_type is None:
328 raise errors.MissingResponseTypeError(request=request)
329 # Value MUST be one of our registered types: "token" by default or if using OIDC "id_token" or "id_token token"
330 elif not set(request.response_type.split()).issubset(self.response_types):
331 raise errors.UnsupportedResponseTypeError(request=request)
333 log.debug('Validating use of response_type token for client %r (%r).',
334 request.client_id, request.client)
335 if not self.request_validator.validate_response_type(request.client_id,
336 request.response_type,
337 request.client, request):
339 log.debug('Client %s is not authorized to use response_type %s.',
340 request.client_id, request.response_type)
341 raise errors.UnauthorizedClientError(request=request)
343 # OPTIONAL. The scope of the access request as described by Section 3.3
344 # https://tools.ietf.org/html/rfc6749#section-3.3
345 self.validate_scopes(request)
347 request_info.update({
348 'client_id': request.client_id,
349 'redirect_uri': request.redirect_uri,
350 'response_type': request.response_type,
351 'state': request.state,
352 'request': request,
353 })
355 request_info = self._run_custom_validators(
356 request,
357 self.custom_validators.all_post,
358 request_info
359 )
361 return request.scopes, request_info
363 def _run_custom_validators(self,
364 request,
365 validations,
366 request_info=None):
367 # Make a copy so we don't modify the existing request_info dict
368 request_info = {} if request_info is None else request_info.copy()
369 # For implicit grant, auth_validators and token_validators are
370 # basically equivalent since the token is returned from the
371 # authorization endpoint.
372 for validator in validations:
373 result = validator(request)
374 if result is not None:
375 request_info.update(result)
376 return request_info