diff --git a/docs/oauth2/endpoints/device.rst b/docs/oauth2/endpoints/device.rst index 728fd3c2..c88437a1 100644 --- a/docs/oauth2/endpoints/device.rst +++ b/docs/oauth2/endpoints/device.rst @@ -22,12 +22,21 @@ the device authorization endpoint. from your_validator import your_validator verification_uri = "https://example.com/device" + # verification_uri_complete can either be a callable that receives user code as an arg + # or a string (e.g verification_uri_complete = "https://example.com/device=1234") + verification_uri_complete = lambda user_code: f"https://example.com/device={user_code}" + def user_code(): # some logic to generate a random string... return "123-456" # user code is optional - server = DeviceApplicationServer(your_validator, verification_uri, user_code) + server = DeviceApplicationServer( + request_validator=your_validator, + verification_uri=verification_uri, + verification_uri_complete=verification_uri_complete, + user_code=user_code + ) headers, data, status = server.create_device_authorization_response(request) diff --git a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py index ef7db0c9..8f6aa32b 100644 --- a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py +++ b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py @@ -57,7 +57,7 @@ def __init__( self.password_grant = ResourceOwnerPasswordCredentialsGrant(request_validator) self.credentials_grant = ClientCredentialsGrant(request_validator) self.refresh_grant = RefreshTokenGrant(request_validator) - self.device_code_grant = DeviceCodeGrant(request_validator) + self.device_code_grant = DeviceCodeGrant(request_validator, **kwargs) self.bearer = BearerToken( request_validator, token_generator, token_expires_in, refresh_token_generator diff --git a/oauthlib/oauth2/rfc8628/clients/device.py b/oauthlib/oauth2/rfc8628/clients/device.py index b9ba2150..ee0ccf8d 100644 --- a/oauthlib/oauth2/rfc8628/clients/device.py +++ b/oauthlib/oauth2/rfc8628/clients/device.py @@ -45,9 +45,9 @@ def prepare_request_uri(self, uri, scope=None, **kwargs): if scope: params.append(('scope', list_to_scope(scope))) - for k in kwargs: - if kwargs[k]: - params.append((str(k), kwargs[k])) + for k,v in kwargs.items(): + if v: + params.append((str(k), v)) return add_params_to_uri(uri, params) diff --git a/oauthlib/oauth2/rfc8628/endpoints/device_authorization.py b/oauthlib/oauth2/rfc8628/endpoints/device_authorization.py index 7cda5ee1..3f38a540 100644 --- a/oauthlib/oauth2/rfc8628/endpoints/device_authorization.py +++ b/oauthlib/oauth2/rfc8628/endpoints/device_authorization.py @@ -224,6 +224,7 @@ def create_device_authorization_response( 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 diff --git a/oauthlib/oauth2/rfc8628/endpoints/pre_configured.py b/oauthlib/oauth2/rfc8628/endpoints/pre_configured.py index bfc6c404..6cce6833 100644 --- a/oauthlib/oauth2/rfc8628/endpoints/pre_configured.py +++ b/oauthlib/oauth2/rfc8628/endpoints/pre_configured.py @@ -1,7 +1,8 @@ from oauthlib.oauth2.rfc8628.endpoints.device_authorization import ( DeviceAuthorizationEndpoint, ) -from typing import Callable + +from typing import Callable, Optional from oauthlib.openid.connect.core.request_validator import RequestValidator @@ -13,6 +14,7 @@ def __init__( 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, ): @@ -30,4 +32,5 @@ def __init__( interval=interval, verification_uri=verification_uri, user_code_generator=user_code_generator, + verification_uri_complete=verification_uri_complete, ) diff --git a/oauthlib/oauth2/rfc8628/grant_types/device_code.py b/oauthlib/oauth2/rfc8628/grant_types/device_code.py index 8e4393d3..082daf0f 100644 --- a/oauthlib/oauth2/rfc8628/grant_types/device_code.py +++ b/oauthlib/oauth2/rfc8628/grant_types/device_code.py @@ -3,7 +3,7 @@ from typing import Callable -from oauthlib import common # noqa: TCH001 +from oauthlib import common # noqa: TC001 from oauthlib.oauth2.rfc6749 import errors as rfc6749_errors from oauthlib.oauth2.rfc6749.grant_types.base import GrantTypeBase diff --git a/oauthlib/openid/connect/core/endpoints/pre_configured.py b/oauthlib/openid/connect/core/endpoints/pre_configured.py index 62983014..17df516d 100644 --- a/oauthlib/openid/connect/core/endpoints/pre_configured.py +++ b/oauthlib/openid/connect/core/endpoints/pre_configured.py @@ -80,7 +80,7 @@ def __init__( self.openid_connect_auth = AuthorizationCodeGrant(request_validator) self.openid_connect_implicit = ImplicitGrant(request_validator) self.openid_connect_hybrid = HybridGrant(request_validator) - self.device_code_grant = DeviceCodeGrant(request_validator) + self.device_code_grant = DeviceCodeGrant(request_validator, **kwargs) self.bearer = BearerToken( request_validator, token_generator, token_expires_in, refresh_token_generator diff --git a/ruff.toml b/ruff.toml index 443f123e..0546d652 100644 --- a/ruff.toml +++ b/ruff.toml @@ -98,6 +98,12 @@ max-complexity = 24 # default is 10 "oauthlib/oauth2/rfc6749/endpoints/base.py" = ["BLE001"] "oauthlib/openid/connect/core/grant_types/base.py" = ["BLE001"] "tests/*" = ["PT009", "PT027", "S101"] +"oauthlib/oauth1/rfc5849/endpoints/resource.py" = ["A005"] +"oauthlib/oauth2/rfc6749/endpoints/resource.py" = ["A005"] +"oauthlib/oauth2/rfc6749/endpoints/token.py" = ["A005"] +"oauthlib/oauth2/rfc6749/parameters.py" = ["PLC0206"] +"oauthlib/oauth2/rfc6749/tokens.py" = ["RUF023"] +"oauthlib/openid/connect/core/tokens.py" = ["RUF023"] # [tool.ruff.pylint] [pylint] diff --git a/tests/oauth2/rfc8628/endpoints/test_device_application_server.py b/tests/oauth2/rfc8628/endpoints/test_device_application_server.py new file mode 100644 index 00000000..f0436754 --- /dev/null +++ b/tests/oauth2/rfc8628/endpoints/test_device_application_server.py @@ -0,0 +1,26 @@ +import json +from unittest import TestCase, mock + +from oauthlib.common import Request, urlencode +from oauthlib.oauth2.rfc6749 import errors +from oauthlib.oauth2.rfc8628.endpoints.pre_configured import DeviceApplicationServer +from oauthlib.oauth2.rfc8628.request_validator import RequestValidator + + +def test_server_set_up_device_endpoint_instance_attributes_correctly(): + """ + Simple test that just instantiates DeviceApplicationServer + and asserts the important attributes are present + """ + validator = mock.MagicMock(spec=RequestValidator) + validator.get_default_redirect_uri.return_value = None + validator.get_code_challenge.return_value = None + + verification_uri = "test.com/device" + verification_uri_complete = "test.com/device?user_code=123" + device = DeviceApplicationServer(validator, verification_uri=verification_uri, verification_uri_complete=verification_uri_complete) + device_vars = vars(device) + assert device_vars["_verification_uri_complete"] == "test.com/device?user_code=123" + assert device_vars["_verification_uri"] == "test.com/device" + assert device_vars["_expires_in"] == 1800 + assert device_vars["_interval"] == 5
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: