Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions oauthlib/oauth2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,6 @@
from .rfc6749.tokens import BearerToken, OAuth2Token
from .rfc6749.utils import is_secure_transport
from .rfc8628.clients import DeviceClient
from oauthlib.oauth2.rfc8628.endpoints import DeviceAuthorizationEndpoint, DeviceApplicationServer
from oauthlib.oauth2.rfc8628.grant_types import DeviceCodeGrant
from .rfc8628.endpoints import DeviceAuthorizationEndpoint, DeviceApplicationServer
Copy link

Copilot AI Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Imports from the rfc8628 subpackage are not grouped alphabetically with the existing imports; consider organizing import order to match project style guidelines for readability.

Copilot uses AI. Check for mistakes.
from .rfc8628.errors import AuthorizationPendingError, SlowDownError, ExpiredTokenError, AccessDenied
from .rfc8628.grant_types import DeviceCodeGrant
16 changes: 1 addition & 15 deletions oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,21 +452,7 @@ def validate_token_request(self, request):
raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param,
request=request)

if self.request_validator.client_authentication_required(request):
# If the client type is confidential or the client was issued client
# credentials (or assigned other authentication requirements), the
# client MUST authenticate with the authorization server as described
# in Section 3.2.1.
# https://tools.ietf.org/html/rfc6749#section-3.2.1
if not self.request_validator.authenticate_client(request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)
elif not self.request_validator.authenticate_client_id(request.client_id, request):
# REQUIRED, if the client is not authenticating with the
# authorization server as described in Section 3.2.1.
# https://tools.ietf.org/html/rfc6749#section-3.2.1
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)
self.validate_client_authentication(request)

if not hasattr(request.client, 'client_id'):
raise NotImplementedError('Authenticate client must set the '
Expand Down
21 changes: 21 additions & 0 deletions oauthlib/oauth2/rfc6749/grant_types/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,27 @@ def validate_scopes(self, request):
request.scopes, request.client, request):
raise errors.InvalidScopeError(request=request)

def validate_client_authentication(self, request):
"""Raise on failed client authentication."""
# Handles confidential clients
if self.request_validator.client_authentication_required(request):
# If the client type is confidential or the client was issued client
# credentials (or assigned other authentication requirements), the
# client MUST authenticate with the authorization server as described
# in Section 3.2.1.
# https://tools.ietf.org/html/rfc6749#section-3.2.1
if not self.request_validator.authenticate_client(request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)

# Handles public clients
elif not self.request_validator.authenticate_client_id(request.client_id, request):
Copy link

Copilot AI Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate_client_authentication invokes authenticate_client_id without checking if request.client_id is set; if client_id is None, this may raise an unexpected exception. Consider adding an explicit guard or raising an InvalidClientError when request.client_id is missing before calling authenticate_client_id.

Copilot uses AI. Check for mistakes.
# REQUIRED, if the client is not authenticating with the
# authorization server as described in Section 3.2.1.
# https://tools.ietf.org/html/rfc6749#section-3.2.1
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)

def prepare_authorization_response(self, request, token, headers, body, status):
"""Place token according to response mode.

Expand Down
16 changes: 5 additions & 11 deletions oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,11 @@ def validate_token_request(self, request):
# authentication requirements), the client MUST authenticate with the
# authorization server as described in Section 3.2.1.
# https://tools.ietf.org/html/rfc6749#section-3.2.1
if self.request_validator.client_authentication_required(request):
log.debug('Authenticating client, %r.', request)
if not self.request_validator.authenticate_client(request):
log.debug('Invalid client (%r), denying access.', request)
raise errors.InvalidClientError(request=request)
# Ensure that request.client_id is set.
if request.client_id is None and request.client is not None:
request.client_id = request.client.client_id
elif not self.request_validator.authenticate_client_id(request.client_id, request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)
self.validate_client_authentication(request)

# Ensure that request.client_id is set.
if request.client_id is None and request.client is not None:
request.client_id = request.client.client_id

# Ensure client is authorized use of this grant type
self.validate_grant_type(request)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,7 @@ def create_token_response(self, request, token_handler):
"""
headers = self._get_default_headers()
try:
if self.request_validator.client_authentication_required(request):
log.debug('Authenticating client, %r.', request)
if not self.request_validator.authenticate_client(request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)
elif not self.request_validator.authenticate_client_id(request.client_id, request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)
self.validate_client_authentication(request)
log.debug('Validating access token request, %r.', request)
self.validate_token_request(request)
except errors.OAuth2Error as e:
Expand Down
20 changes: 6 additions & 14 deletions oauthlib/oauth2/rfc8628/grant_types/device_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,12 @@ def validate_token_request(self, request: common.Request) -> None:
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."
)
self.validate_client_authentication(request)

if 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)
Expand Down Expand Up @@ -93,13 +91,7 @@ def create_token_response(
"""
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)
Comment on lines -96 to -99
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This already happens inside self.validate_token_request(request) below.


self.validate_token_request(request)

except rfc6749_errors.OAuth2Error as e:
headers.update(e.headers)
return headers, e.json, e.status_code
Expand Down
31 changes: 30 additions & 1 deletion tests/oauth2/rfc8628/grant_types/test_device_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,16 @@ def test_create_token_response():
validator.save_token.assert_called_once()


def test_invalid_client_error():
def test_invalid_client_authentication_error_confidential_client():
validator = mock.MagicMock()
request: common.Request = create_request()
request.client = mock.Mock()

auth = DeviceCodeGrant(validator)
bearer = BearerToken(validator)

# Simulate a confidential client that requires authentication
validator.client_authentication_required.return_value = True
validator.authenticate_client.return_value = False

headers, body, status_code = auth.create_token_response(request, bearer)
Expand All @@ -124,6 +126,33 @@ def test_invalid_client_error():
validator.save_token.assert_not_called()


def test_invalid_client_authentication_error_public_client():
validator = mock.MagicMock()
request: common.Request = create_request()
request.client = mock.Mock()

auth = DeviceCodeGrant(validator)
bearer = BearerToken(validator)

# Simulate a public client that does not require authentication
validator.client_authentication_required.return_value = False
validator.authenticate_client_id.return_value = False

headers, body, status_code = auth.create_token_response(request, bearer)
body = json.loads(body)

assert headers == {
"Content-Type": "application/json",
"Cache-Control": "no-store",
"Pragma": "no-cache",
"WWW-Authenticate": 'Bearer error="invalid_client"',
}
assert body == {"error": "invalid_client"}
assert status_code == 401

validator.save_token.assert_not_called()


def test_invalid_grant_type_error():
validator = mock.MagicMock()
request: common.Request = create_request()
Expand Down
Loading