chore: 添加虚拟环境到仓库
- 添加 backend_service/venv 虚拟环境 - 包含所有Python依赖包 - 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
oauthlib.oauth2.rfc8628
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 Device Authorization RFC8628.
|
||||
"""
|
||||
|
||||
from oauthlib.oauth2.rfc8628.errors import (
|
||||
SlowDownError,
|
||||
AuthorizationPendingError,
|
||||
ExpiredTokenError,
|
||||
)
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
oauthlib.oauth2.rfc8628
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming OAuth 2.0 Device Authorization RFC8628.
|
||||
"""
|
||||
from .device import DeviceClient
|
||||
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
oauthlib.oauth2.rfc8628
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 Device Authorization RFC8628.
|
||||
"""
|
||||
from oauthlib.common import add_params_to_uri
|
||||
from oauthlib.oauth2 import BackendApplicationClient, Client
|
||||
from oauthlib.oauth2.rfc6749.errors import InsecureTransportError
|
||||
from oauthlib.oauth2.rfc6749.parameters import prepare_token_request
|
||||
from oauthlib.oauth2.rfc6749.utils import is_secure_transport, list_to_scope
|
||||
|
||||
|
||||
class DeviceClient(Client):
|
||||
|
||||
"""A public client utilizing the device authorization workflow.
|
||||
|
||||
The client can request an access token using a device code and
|
||||
a public client id associated with the device code as defined
|
||||
in RFC8628.
|
||||
|
||||
The device authorization grant type can be used to obtain both
|
||||
access tokens and refresh tokens and is intended to be used in
|
||||
a scenario where the device being authorized does not have a
|
||||
user interface that is suitable for performing authentication.
|
||||
"""
|
||||
|
||||
grant_type = 'urn:ietf:params:oauth:grant-type:device_code'
|
||||
|
||||
def __init__(self, client_id, **kwargs):
|
||||
super().__init__(client_id, **kwargs)
|
||||
self.client_secret = kwargs.get('client_secret')
|
||||
|
||||
def prepare_request_uri(self, uri, scope=None, **kwargs):
|
||||
if not is_secure_transport(uri):
|
||||
raise InsecureTransportError()
|
||||
|
||||
scope = self.scope if scope is None else scope
|
||||
params = [(('client_id', self.client_id)), (('grant_type', self.grant_type))]
|
||||
|
||||
if self.client_secret is not None:
|
||||
params.append(('client_secret', self.client_secret))
|
||||
|
||||
if scope:
|
||||
params.append(('scope', list_to_scope(scope)))
|
||||
|
||||
for k,v in kwargs.items():
|
||||
if v:
|
||||
params.append((str(k), v))
|
||||
|
||||
return add_params_to_uri(uri, params)
|
||||
|
||||
def prepare_request_body(self, device_code, body='', scope=None,
|
||||
include_client_id=False, **kwargs):
|
||||
"""Add device_code to request body
|
||||
|
||||
The client makes a request to the token endpoint by adding the
|
||||
device_code as a parameter using the
|
||||
"application/x-www-form-urlencoded" format to the HTTP request
|
||||
body.
|
||||
|
||||
:param body: Existing request body (URL encoded string) to embed parameters
|
||||
into. This may contain extra parameters. Default ''.
|
||||
:param scope: The scope of the access request as described by
|
||||
`Section 3.3`_.
|
||||
|
||||
:param include_client_id: `True` to send the `client_id` in the
|
||||
body of the upstream request. This is required
|
||||
if the client is not authenticating with the
|
||||
authorization server as described in
|
||||
`Section 3.2.1`_. False otherwise (default).
|
||||
:type include_client_id: Boolean
|
||||
|
||||
:param kwargs: Extra credentials to include in the token request.
|
||||
|
||||
The prepared body will include all provided device_code as well as
|
||||
the ``grant_type`` parameter set to
|
||||
``urn:ietf:params:oauth:grant-type:device_code``::
|
||||
|
||||
>>> from oauthlib.oauth2 import DeviceClient
|
||||
>>> client = DeviceClient('your_id', 'your_code')
|
||||
>>> client.prepare_request_body(scope=['hello', 'world'])
|
||||
'grant_type=urn:ietf:params:oauth:grant-type:device_code&scope=hello+world'
|
||||
|
||||
.. _`Section 3.2.1`: https://datatracker.ietf.org/doc/html/rfc6749#section-3.2.1
|
||||
.. _`Section 3.3`: https://datatracker.ietf.org/doc/html/rfc6749#section-3.3
|
||||
.. _`Section 3.4`: https://datatracker.ietf.org/doc/html/rfc8628#section-3.4
|
||||
"""
|
||||
|
||||
kwargs['client_id'] = self.client_id
|
||||
kwargs['include_client_id'] = include_client_id
|
||||
scope = self.scope if scope is None else scope
|
||||
return prepare_token_request(self.grant_type, body=body, device_code=device_code,
|
||||
scope=scope, **kwargs)
|
||||
@@ -0,0 +1,10 @@
|
||||
"""
|
||||
oauthlib.oauth2.rfc8628
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 Device Authorization RFC8628.
|
||||
"""
|
||||
|
||||
from .device_authorization import DeviceAuthorizationEndpoint
|
||||
from .pre_configured import DeviceApplicationServer
|
||||
@@ -0,0 +1,232 @@
|
||||
"""
|
||||
oauthlib.oauth2.rfc8628
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 RFC8628.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
from oauthlib.common import Request, generate_token
|
||||
from oauthlib.oauth2.rfc6749 import errors
|
||||
from oauthlib.oauth2.rfc6749.endpoints.base import (
|
||||
BaseEndpoint,
|
||||
catch_errors_and_unavailability,
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeviceAuthorizationEndpoint(BaseEndpoint):
|
||||
"""DeviceAuthorization endpoint - used by the client to initiate
|
||||
the authorization flow by requesting a set of verification codes
|
||||
from the authorization server by making an HTTP "POST" request to
|
||||
the device authorization endpoint.
|
||||
|
||||
The client authentication requirements of Section 3.2.1 of [RFC6749]
|
||||
apply to requests on this endpoint, which means that confidential
|
||||
clients (those that have established client credentials) authenticate
|
||||
in the same manner as when making requests to the token endpoint, and
|
||||
public clients provide the "client_id" parameter to identify
|
||||
themselves.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
request_validator,
|
||||
verification_uri,
|
||||
expires_in=1800,
|
||||
interval=None,
|
||||
verification_uri_complete=None,
|
||||
user_code_generator: Callable[[None], str] = None,
|
||||
):
|
||||
"""
|
||||
:param request_validator: An instance of RequestValidator.
|
||||
:type request_validator: oauthlib.oauth2.rfc6749.RequestValidator.
|
||||
:param verification_uri: a string containing the URL that can be polled by the client application
|
||||
:param expires_in: a number that represents the lifetime of the `user_code` and `device_code`
|
||||
:param interval: an option number that represents the number of seconds between each poll requests
|
||||
:param verification_uri_complete: a string of a function that can be called with `user_data` as parameter
|
||||
:param user_code_generator: a callable that returns a configurable user code
|
||||
"""
|
||||
self.request_validator = request_validator
|
||||
self._expires_in = expires_in
|
||||
self._interval = interval
|
||||
self._verification_uri = verification_uri
|
||||
self._verification_uri_complete = verification_uri_complete
|
||||
self.user_code_generator = user_code_generator
|
||||
|
||||
BaseEndpoint.__init__(self)
|
||||
|
||||
@property
|
||||
def interval(self):
|
||||
"""The minimum amount of time in seconds that the client
|
||||
SHOULD wait between polling requests to the token endpoint. If no
|
||||
value is provided, clients MUST use 5 as the default.
|
||||
"""
|
||||
return self._interval
|
||||
|
||||
@property
|
||||
def expires_in(self):
|
||||
"""The lifetime in seconds of the "device_code" and "user_code"."""
|
||||
return self._expires_in
|
||||
|
||||
@property
|
||||
def verification_uri(self):
|
||||
"""The end-user verification URI on the authorization
|
||||
server. The URI should be short and easy to remember as end users
|
||||
will be asked to manually type it into their user agent.
|
||||
"""
|
||||
return self._verification_uri
|
||||
|
||||
def verification_uri_complete(self, user_code):
|
||||
if not self._verification_uri_complete:
|
||||
return None
|
||||
if isinstance(self._verification_uri_complete, str):
|
||||
return self._verification_uri_complete.format(user_code=user_code)
|
||||
if callable(self._verification_uri_complete):
|
||||
return self._verification_uri_complete(user_code)
|
||||
return None
|
||||
|
||||
@catch_errors_and_unavailability
|
||||
def validate_device_authorization_request(self, request):
|
||||
"""Validate the device authorization request.
|
||||
|
||||
The client_id is required if the client is not authenticating with the
|
||||
authorization server as described in `Section 3.2.1. of [RFC6749]`_.
|
||||
The client identifier as described in `Section 2.2 of [RFC6749]`_.
|
||||
|
||||
.. _`Section 3.2.1. of [RFC6749]`: https://www.rfc-editor.org/rfc/rfc6749#section-3.2.1
|
||||
.. _`Section 2.2 of [RFC6749]`: https://www.rfc-editor.org/rfc/rfc6749#section-2.2
|
||||
"""
|
||||
|
||||
# First check duplicate parameters
|
||||
for param in ("client_id", "scope"):
|
||||
try:
|
||||
duplicate_params = request.duplicate_params
|
||||
except ValueError:
|
||||
raise errors.InvalidRequestFatalError(
|
||||
description="Unable to parse query string", request=request
|
||||
)
|
||||
if param in duplicate_params:
|
||||
raise errors.InvalidRequestFatalError(
|
||||
description="Duplicate %s parameter." % param, request=request
|
||||
)
|
||||
|
||||
# the "application/x-www-form-urlencoded" format, per Appendix B of [RFC6749]
|
||||
# https://www.rfc-editor.org/rfc/rfc6749#appendix-B
|
||||
if request.headers["Content-Type"] != "application/x-www-form-urlencoded":
|
||||
raise errors.InvalidRequestError(
|
||||
"Content-Type must be application/x-www-form-urlencoded",
|
||||
request=request,
|
||||
)
|
||||
|
||||
# REQUIRED. The client identifier as described in Section 2.2.
|
||||
# https://tools.ietf.org/html/rfc6749#section-2.2
|
||||
# TODO: extract client_id an helper validation function.
|
||||
if not request.client_id:
|
||||
raise errors.MissingClientIdError(request=request)
|
||||
|
||||
if not self.request_validator.validate_client_id(request.client_id, request):
|
||||
raise errors.InvalidClientIdError(request=request)
|
||||
|
||||
# The client authentication requirements of Section 3.2.1 of [RFC6749]
|
||||
# apply to requests on this endpoint, which means that confidential
|
||||
# clients (those that have established client credentials) authenticate
|
||||
# in the same manner as when making requests to the token endpoint, and
|
||||
# public clients provide the "client_id" parameter to identify
|
||||
# themselves.
|
||||
self._raise_on_invalid_client(request)
|
||||
|
||||
@catch_errors_and_unavailability
|
||||
def create_device_authorization_response(
|
||||
self, uri, http_method="POST", body=None, headers=None
|
||||
):
|
||||
"""
|
||||
Generate a unique device verification code and an end-user code that are valid for a limited time.
|
||||
Include them in the HTTP response body using the "application/json" format [RFC8259] with a
|
||||
200 (OK) status code, as described in `Section-3.2`_.
|
||||
|
||||
:param uri: The full URI of the token request.
|
||||
:type uri: str
|
||||
:param request: OAuthlib request.
|
||||
:type request: oauthlib.common.Request
|
||||
:param user_code_generator:
|
||||
A callable that returns a string for the user code.
|
||||
This allows the caller to decide how the `user_code` should be formatted.
|
||||
:type user_code_generator: Callable[[], str]
|
||||
:return: A tuple of three elements:
|
||||
1. A dict of headers to set on the response.
|
||||
2. The response body as a string.
|
||||
3. The response status code as an integer.
|
||||
:rtype: tuple
|
||||
|
||||
The response contains the following parameters:
|
||||
|
||||
device_code
|
||||
**REQUIRED.** The device verification code.
|
||||
|
||||
user_code
|
||||
**REQUIRED.** The end-user verification code.
|
||||
|
||||
verification_uri
|
||||
**REQUIRED.** The end-user verification URI on the authorization server.
|
||||
The URI should be short and easy to remember as end users will be asked
|
||||
to manually type it into their user agent.
|
||||
|
||||
verification_uri_complete
|
||||
**OPTIONAL.** A verification URI that includes the `user_code` (or
|
||||
other information with the same function as the `user_code`), which is
|
||||
designed for non-textual transmission.
|
||||
|
||||
expires_in
|
||||
**REQUIRED.** The lifetime in seconds of the `device_code` and `user_code`.
|
||||
|
||||
interval
|
||||
**OPTIONAL.** The minimum amount of time in seconds that the client
|
||||
SHOULD wait between polling requests to the token endpoint. If no
|
||||
value is provided, clients MUST use 5 as the default.
|
||||
|
||||
**For example:**
|
||||
|
||||
.. code-block:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Cache-Control: no-store
|
||||
|
||||
{
|
||||
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
|
||||
"user_code": "WDJB-MJHT",
|
||||
"verification_uri": "https://example.com/device",
|
||||
"verification_uri_complete":
|
||||
"https://example.com/device?user_code=WDJB-MJHT",
|
||||
"expires_in": 1800,
|
||||
"interval": 5
|
||||
}
|
||||
|
||||
.. _`Section-3.2`: https://www.rfc-editor.org/rfc/rfc8628#section-3.2
|
||||
"""
|
||||
request = Request(uri, http_method, body, headers)
|
||||
self.validate_device_authorization_request(request)
|
||||
log.debug("Pre resource owner authorization validation ok for %r.", request)
|
||||
|
||||
headers = {}
|
||||
user_code = self.user_code_generator() if self.user_code_generator else generate_token()
|
||||
data = {
|
||||
"verification_uri": self.verification_uri,
|
||||
"expires_in": self.expires_in,
|
||||
"user_code": user_code,
|
||||
"device_code": generate_token(),
|
||||
}
|
||||
if self.interval is not None:
|
||||
data["interval"] = self.interval
|
||||
|
||||
|
||||
verification_uri_complete = self.verification_uri_complete(user_code)
|
||||
if verification_uri_complete:
|
||||
data["verification_uri_complete"] = verification_uri_complete
|
||||
|
||||
return headers, data, 200
|
||||
@@ -0,0 +1,36 @@
|
||||
from oauthlib.oauth2.rfc8628.endpoints.device_authorization import (
|
||||
DeviceAuthorizationEndpoint,
|
||||
)
|
||||
|
||||
from typing import Callable, Optional
|
||||
from oauthlib.openid.connect.core.request_validator import RequestValidator
|
||||
|
||||
|
||||
class DeviceApplicationServer(DeviceAuthorizationEndpoint):
|
||||
"""An all-in-one endpoint featuring Authorization code grant and Bearer tokens."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
request_validator: RequestValidator,
|
||||
verification_uri: str,
|
||||
interval: int = 5,
|
||||
verification_uri_complete: Optional[str] = None, # noqa: FA100
|
||||
user_code_generator: Callable[[None], str] = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""Construct a new web application server.
|
||||
|
||||
:param request_validator: An implementation of
|
||||
oauthlib.oauth2.rfc8626.RequestValidator.
|
||||
:param interval: How long the device needs to wait before polling the server
|
||||
:param verification_uri: the verification_uri to be send back.
|
||||
:param user_code_generator: a callable that allows the user code to be configured.
|
||||
"""
|
||||
DeviceAuthorizationEndpoint.__init__(
|
||||
self,
|
||||
request_validator,
|
||||
interval=interval,
|
||||
verification_uri=verification_uri,
|
||||
user_code_generator=user_code_generator,
|
||||
verification_uri_complete=verification_uri_complete,
|
||||
)
|
||||
@@ -0,0 +1,55 @@
|
||||
from oauthlib.oauth2.rfc6749.errors import OAuth2Error
|
||||
|
||||
"""
|
||||
oauthlib.oauth2.rfc8628.errors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Error used both by OAuth2 clients and providers to represent the spec
|
||||
defined error responses specific to the the device grant
|
||||
"""
|
||||
|
||||
|
||||
class AuthorizationPendingError(OAuth2Error):
|
||||
"""
|
||||
For the device authorization grant;
|
||||
The authorization request is still pending as the end user hasn't
|
||||
yet completed the user-interaction steps (Section 3.3). The
|
||||
client SHOULD repeat the access token request to the token
|
||||
endpoint (a process known as polling). Before each new request,
|
||||
the client MUST wait at least the number of seconds specified by
|
||||
the "interval" parameter of the device authorization response,
|
||||
or 5 seconds if none was provided, and respect any
|
||||
increase in the polling interval required by the "slow_down"
|
||||
error.
|
||||
"""
|
||||
|
||||
error = "authorization_pending"
|
||||
|
||||
|
||||
class SlowDownError(OAuth2Error):
|
||||
"""
|
||||
A variant of "authorization_pending", the authorization request is
|
||||
still pending and polling should continue, but the interval MUST
|
||||
be increased by 5 seconds for this and all subsequent requests.
|
||||
"""
|
||||
|
||||
error = "slow_down"
|
||||
|
||||
|
||||
class ExpiredTokenError(OAuth2Error):
|
||||
"""
|
||||
The "device_code" has expired, and the device authorization
|
||||
session has concluded. The client MAY commence a new device
|
||||
authorization request but SHOULD wait for user interaction before
|
||||
restarting to avoid unnecessary polling.
|
||||
"""
|
||||
|
||||
error = "expired_token"
|
||||
|
||||
|
||||
class AccessDenied(OAuth2Error):
|
||||
"""
|
||||
The authorization request was denied.
|
||||
"""
|
||||
|
||||
error = "access_denied"
|
||||
@@ -0,0 +1 @@
|
||||
from oauthlib.oauth2.rfc8628.grant_types.device_code import DeviceCodeGrant
|
||||
@@ -0,0 +1,111 @@
|
||||
from __future__ import annotations
|
||||
import json
|
||||
|
||||
from typing import Callable
|
||||
|
||||
from oauthlib import common # noqa: TC001
|
||||
|
||||
from oauthlib.oauth2.rfc6749 import errors as rfc6749_errors
|
||||
from oauthlib.oauth2.rfc6749.grant_types.base import GrantTypeBase
|
||||
|
||||
|
||||
class DeviceCodeGrant(GrantTypeBase):
|
||||
def create_authorization_response(
|
||||
self, request: common.Request, token_handler: Callable
|
||||
) -> tuple[dict, str, int]:
|
||||
"""
|
||||
Validate the device flow request -> create the access token
|
||||
-> persist the token -> return the token.
|
||||
"""
|
||||
headers = self._get_default_headers()
|
||||
try:
|
||||
self.validate_token_request(request)
|
||||
except rfc6749_errors.OAuth2Error as e:
|
||||
headers.update(e.headers)
|
||||
return headers, e.json, e.status_code
|
||||
|
||||
token = token_handler.create_token(request, refresh_token=False)
|
||||
|
||||
for modifier in self._token_modifiers:
|
||||
token = modifier(token)
|
||||
|
||||
self.request_validator.save_token(token, request)
|
||||
|
||||
return self.create_token_response(request, token_handler)
|
||||
|
||||
def validate_token_request(self, request: common.Request) -> None:
|
||||
"""
|
||||
Performs the necessary check against the request to ensure
|
||||
it's allowed to retrieve a token.
|
||||
"""
|
||||
for validator in self.custom_validators.pre_token:
|
||||
validator(request)
|
||||
|
||||
if not getattr(request, "grant_type", None):
|
||||
raise rfc6749_errors.InvalidRequestError(
|
||||
"Request is missing grant type.", request=request
|
||||
)
|
||||
|
||||
if request.grant_type != "urn:ietf:params:oauth:grant-type:device_code":
|
||||
raise rfc6749_errors.UnsupportedGrantTypeError(request=request)
|
||||
|
||||
for param in ("grant_type", "scope"):
|
||||
if param in request.duplicate_params:
|
||||
raise rfc6749_errors.InvalidRequestError(
|
||||
description=f"Duplicate {param} parameter.", request=request
|
||||
)
|
||||
|
||||
if not self.request_validator.authenticate_client(request):
|
||||
raise rfc6749_errors.InvalidClientError(request=request)
|
||||
elif not hasattr(request.client, "client_id"):
|
||||
raise NotImplementedError(
|
||||
"Authenticate client must set the "
|
||||
"request.client.client_id attribute "
|
||||
"in authenticate_client."
|
||||
)
|
||||
|
||||
# Ensure client is authorized use of this grant type
|
||||
self.validate_grant_type(request)
|
||||
|
||||
request.client_id = request.client_id or request.client.client_id
|
||||
self.validate_scopes(request)
|
||||
|
||||
for validator in self.custom_validators.post_token:
|
||||
validator(request)
|
||||
|
||||
def create_token_response(
|
||||
self, request: common.Request, token_handler: Callable
|
||||
) -> tuple[dict, str, int]:
|
||||
"""Return token or error in json format.
|
||||
|
||||
:param request: OAuthlib request.
|
||||
:type request: oauthlib.common.Request
|
||||
:param token_handler: A token handler instance, for example of type
|
||||
oauthlib.oauth2.BearerToken.
|
||||
|
||||
If the access token request is valid and authorized, the
|
||||
authorization server issues an access token and optional refresh
|
||||
token as described in `Section 5.1`_. If the request failed client
|
||||
authentication or is invalid, the authorization server returns an
|
||||
error response as described in `Section 5.2`_.
|
||||
.. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1
|
||||
.. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2
|
||||
"""
|
||||
headers = self._get_default_headers()
|
||||
try:
|
||||
if self.request_validator.client_authentication_required(
|
||||
request
|
||||
) and not self.request_validator.authenticate_client(request):
|
||||
raise rfc6749_errors.InvalidClientError(request=request)
|
||||
|
||||
self.validate_token_request(request)
|
||||
|
||||
except rfc6749_errors.OAuth2Error as e:
|
||||
headers.update(e.headers)
|
||||
return headers, e.json, e.status_code
|
||||
|
||||
token = token_handler.create_token(request, self.refresh_token)
|
||||
|
||||
self.request_validator.save_token(token, request)
|
||||
|
||||
return headers, json.dumps(token), 200
|
||||
@@ -0,0 +1,25 @@
|
||||
from oauthlib.oauth2 import RequestValidator as OAuth2RequestValidator
|
||||
|
||||
|
||||
class RequestValidator(OAuth2RequestValidator):
|
||||
def client_authentication_required(self, request, *args, **kwargs):
|
||||
"""Determine if client authentication is required for current request.
|
||||
|
||||
According to the rfc8628, client authentication is required in the following cases:
|
||||
- Device Authorization Request follows the, the client authentication requirements
|
||||
of Section 3.2.1 of [RFC6749] apply to requests on this endpoint, which means that
|
||||
confidential clients (those that have established client credentials) authenticate
|
||||
in the same manner as when making requests to the token endpoint, and
|
||||
public clients provide the "client_id" parameter to identify themselves,
|
||||
see `Section 3.1`_.
|
||||
|
||||
:param request: OAuthlib request.
|
||||
:type request: oauthlib.common.Request
|
||||
:rtype: True or False
|
||||
|
||||
Method is used by:
|
||||
- Device Authorization Request
|
||||
|
||||
.. _`Section 3.1`: https://www.rfc-editor.org/rfc/rfc8628#section-3.1
|
||||
"""
|
||||
return True
|
||||
Reference in New Issue
Block a user