Skip to content

Add DeviceCodeGrant type for device code flow(rfc8628) section 3.4 & 3.5 #889

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 8, 2024
Merged
6 changes: 6 additions & 0 deletions docs/oauth2/grants/device_code.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Device code Grant
-----------------

.. autoclass:: oauthlib.oauth2.DeviceCodeGrant
:members:
:inherited-members:
8 changes: 8 additions & 0 deletions docs/oauth2/grants/grants.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Grant types
password
credentials
refresh
device_code
jwt
custom_validators
custom_grant
Expand All @@ -26,6 +27,13 @@ degree of trust between the resource owner and the client, and when
other authorization grant types are not available. This is also often
used for legacy applications to incrementally transition to OAuth 2.

The device code grant(officially referred to as 'urn:ietf:params:oauth:grant-type:device_code')
is used when trying to authenticate device with limited or no input capabilities by getting
the user to approve the login on an external device (like a mobile phone or laptop) in their
possession that they're already logged into. Unlike the previously mentioned grants it is an extension grant, which is a type of grant
to address specific authorization scenarios.
:doc:`Device code grant </oauth2/grants/device_code>`

The main purpose of the grant types is to authorize access to protected
resources in various ways with different security credentials.

Expand Down
3 changes: 2 additions & 1 deletion oauthlib/oauth2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,5 @@
from .rfc6749.tokens import BearerToken, OAuth2Token
from .rfc6749.utils import is_secure_transport
from .rfc8628.clients import DeviceClient
from .rfc8628.endpoints import DeviceAuthorizationEndpoint, DeviceApplicationServer
from oauthlib.oauth2.rfc8628.endpoints import DeviceAuthorizationEndpoint, DeviceApplicationServer
from oauthlib.oauth2.rfc8628.grant_types import DeviceCodeGrant
275 changes: 173 additions & 102 deletions oauthlib/oauth2/rfc6749/endpoints/pre_configured.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,40 @@
This module is an implementation of various endpoints needed
for providing OAuth 2.0 RFC6749 servers.
"""

from ..grant_types import (
AuthorizationCodeGrant, ClientCredentialsGrant, ImplicitGrant,
RefreshTokenGrant, ResourceOwnerPasswordCredentialsGrant,
AuthorizationCodeGrant,
ClientCredentialsGrant,
ImplicitGrant,
RefreshTokenGrant,
ResourceOwnerPasswordCredentialsGrant,
)
from ..tokens import BearerToken
from .authorization import AuthorizationEndpoint
from .introspect import IntrospectEndpoint
from .resource import ResourceEndpoint
from .revocation import RevocationEndpoint
from .token import TokenEndpoint
from oauthlib.oauth2.rfc8628.grant_types import DeviceCodeGrant


class Server(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint,
ResourceEndpoint, RevocationEndpoint):

"""An all-in-one endpoint featuring all four major grant types."""
class Server(
AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint, ResourceEndpoint, RevocationEndpoint
):
"""
An all-in-one endpoint featuring all four major grant types
and extension grants.
"""

def __init__(self, request_validator, token_expires_in=None,
token_generator=None, refresh_token_generator=None,
*args, **kwargs):
def __init__(
self,
request_validator,
token_expires_in=None,
token_generator=None,
refresh_token_generator=None,
*args,
**kwargs,
):
"""Construct a new all-grants-in-one server.

:param request_validator: An implementation of
Expand All @@ -40,43 +54,58 @@ def __init__(self, request_validator, token_expires_in=None,
"""
self.auth_grant = AuthorizationCodeGrant(request_validator)
self.implicit_grant = ImplicitGrant(request_validator)
self.password_grant = ResourceOwnerPasswordCredentialsGrant(
request_validator)
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.bearer = BearerToken(
request_validator, token_generator, token_expires_in, refresh_token_generator
)

AuthorizationEndpoint.__init__(
self,
default_response_type="code",
response_types={
"code": self.auth_grant,
"token": self.implicit_grant,
"none": self.auth_grant,
},
default_token_type=self.bearer,
)

self.bearer = BearerToken(request_validator, token_generator,
token_expires_in, refresh_token_generator)

AuthorizationEndpoint.__init__(self, default_response_type='code',
response_types={
'code': self.auth_grant,
'token': self.implicit_grant,
'none': self.auth_grant
},
default_token_type=self.bearer)

TokenEndpoint.__init__(self, default_grant_type='authorization_code',
grant_types={
'authorization_code': self.auth_grant,
'password': self.password_grant,
'client_credentials': self.credentials_grant,
'refresh_token': self.refresh_grant,
},
default_token_type=self.bearer)
ResourceEndpoint.__init__(self, default_token='Bearer',
token_types={'Bearer': self.bearer})
TokenEndpoint.__init__(
self,
default_grant_type="authorization_code",
grant_types={
"authorization_code": self.auth_grant,
"password": self.password_grant,
"client_credentials": self.credentials_grant,
"refresh_token": self.refresh_grant,
"urn:ietf:params:oauth:grant-type:device_code": self.device_code_grant,
},
default_token_type=self.bearer,
)
ResourceEndpoint.__init__(
self, default_token="Bearer", token_types={"Bearer": self.bearer}
)
RevocationEndpoint.__init__(self, request_validator)
IntrospectEndpoint.__init__(self, request_validator)


class WebApplicationServer(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint,
ResourceEndpoint, RevocationEndpoint):

class WebApplicationServer(
AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint, ResourceEndpoint, RevocationEndpoint
):
"""An all-in-one endpoint featuring Authorization code grant and Bearer tokens."""

def __init__(self, request_validator, token_generator=None,
token_expires_in=None, refresh_token_generator=None, **kwargs):
def __init__(
self,
request_validator,
token_generator=None,
token_expires_in=None,
refresh_token_generator=None,
**kwargs,
):
"""Construct a new web application server.

:param request_validator: An implementation of
Expand All @@ -92,30 +121,44 @@ def __init__(self, request_validator, token_generator=None,
"""
self.auth_grant = AuthorizationCodeGrant(request_validator)
self.refresh_grant = RefreshTokenGrant(request_validator)
self.bearer = BearerToken(request_validator, token_generator,
token_expires_in, refresh_token_generator)
AuthorizationEndpoint.__init__(self, default_response_type='code',
response_types={'code': self.auth_grant},
default_token_type=self.bearer)
TokenEndpoint.__init__(self, default_grant_type='authorization_code',
grant_types={
'authorization_code': self.auth_grant,
'refresh_token': self.refresh_grant,
},
default_token_type=self.bearer)
ResourceEndpoint.__init__(self, default_token='Bearer',
token_types={'Bearer': self.bearer})
self.bearer = BearerToken(
request_validator, token_generator, token_expires_in, refresh_token_generator
)
AuthorizationEndpoint.__init__(
self,
default_response_type="code",
response_types={"code": self.auth_grant},
default_token_type=self.bearer,
)
TokenEndpoint.__init__(
self,
default_grant_type="authorization_code",
grant_types={
"authorization_code": self.auth_grant,
"refresh_token": self.refresh_grant,
},
default_token_type=self.bearer,
)
ResourceEndpoint.__init__(
self, default_token="Bearer", token_types={"Bearer": self.bearer}
)
RevocationEndpoint.__init__(self, request_validator)
IntrospectEndpoint.__init__(self, request_validator)


class MobileApplicationServer(AuthorizationEndpoint, IntrospectEndpoint,
ResourceEndpoint, RevocationEndpoint):

class MobileApplicationServer(
AuthorizationEndpoint, IntrospectEndpoint, ResourceEndpoint, RevocationEndpoint
):
"""An all-in-one endpoint featuring Implicit code grant and Bearer tokens."""

def __init__(self, request_validator, token_generator=None,
token_expires_in=None, refresh_token_generator=None, **kwargs):
def __init__(
self,
request_validator,
token_generator=None,
token_expires_in=None,
refresh_token_generator=None,
**kwargs,
):
"""Construct a new implicit grant server.

:param request_validator: An implementation of
Expand All @@ -130,27 +173,39 @@ def __init__(self, request_validator, token_generator=None,
token-, resource-, and revocation-endpoint constructors.
"""
self.implicit_grant = ImplicitGrant(request_validator)
self.bearer = BearerToken(request_validator, token_generator,
token_expires_in, refresh_token_generator)
AuthorizationEndpoint.__init__(self, default_response_type='token',
response_types={
'token': self.implicit_grant},
default_token_type=self.bearer)
ResourceEndpoint.__init__(self, default_token='Bearer',
token_types={'Bearer': self.bearer})
RevocationEndpoint.__init__(self, request_validator,
supported_token_types=['access_token'])
IntrospectEndpoint.__init__(self, request_validator,
supported_token_types=['access_token'])


class LegacyApplicationServer(TokenEndpoint, IntrospectEndpoint,
ResourceEndpoint, RevocationEndpoint):
self.bearer = BearerToken(
request_validator, token_generator, token_expires_in, refresh_token_generator
)
AuthorizationEndpoint.__init__(
self,
default_response_type="token",
response_types={"token": self.implicit_grant},
default_token_type=self.bearer,
)
ResourceEndpoint.__init__(
self, default_token="Bearer", token_types={"Bearer": self.bearer}
)
RevocationEndpoint.__init__(
self, request_validator, supported_token_types=["access_token"]
)
IntrospectEndpoint.__init__(
self, request_validator, supported_token_types=["access_token"]
)


class LegacyApplicationServer(
TokenEndpoint, IntrospectEndpoint, ResourceEndpoint, RevocationEndpoint
):
"""An all-in-one endpoint featuring Resource Owner Password Credentials grant and Bearer tokens."""

def __init__(self, request_validator, token_generator=None,
token_expires_in=None, refresh_token_generator=None, **kwargs):
def __init__(
self,
request_validator,
token_generator=None,
token_expires_in=None,
refresh_token_generator=None,
**kwargs,
):
"""Construct a resource owner password credentials grant server.

:param request_validator: An implementation of
Expand All @@ -164,30 +219,40 @@ def __init__(self, request_validator, token_generator=None,
:param kwargs: Extra parameters to pass to authorization-,
token-, resource-, and revocation-endpoint constructors.
"""
self.password_grant = ResourceOwnerPasswordCredentialsGrant(
request_validator)
self.password_grant = ResourceOwnerPasswordCredentialsGrant(request_validator)
self.refresh_grant = RefreshTokenGrant(request_validator)
self.bearer = BearerToken(request_validator, token_generator,
token_expires_in, refresh_token_generator)
TokenEndpoint.__init__(self, default_grant_type='password',
grant_types={
'password': self.password_grant,
'refresh_token': self.refresh_grant,
},
default_token_type=self.bearer)
ResourceEndpoint.__init__(self, default_token='Bearer',
token_types={'Bearer': self.bearer})
self.bearer = BearerToken(
request_validator, token_generator, token_expires_in, refresh_token_generator
)
TokenEndpoint.__init__(
self,
default_grant_type="password",
grant_types={
"password": self.password_grant,
"refresh_token": self.refresh_grant,
},
default_token_type=self.bearer,
)
ResourceEndpoint.__init__(
self, default_token="Bearer", token_types={"Bearer": self.bearer}
)
RevocationEndpoint.__init__(self, request_validator)
IntrospectEndpoint.__init__(self, request_validator)


class BackendApplicationServer(TokenEndpoint, IntrospectEndpoint,
ResourceEndpoint, RevocationEndpoint):

class BackendApplicationServer(
TokenEndpoint, IntrospectEndpoint, ResourceEndpoint, RevocationEndpoint
):
"""An all-in-one endpoint featuring Client Credentials grant and Bearer tokens."""

def __init__(self, request_validator, token_generator=None,
token_expires_in=None, refresh_token_generator=None, **kwargs):
def __init__(
self,
request_validator,
token_generator=None,
token_expires_in=None,
refresh_token_generator=None,
**kwargs,
):
"""Construct a client credentials grant server.

:param request_validator: An implementation of
Expand All @@ -202,15 +267,21 @@ def __init__(self, request_validator, token_generator=None,
token-, resource-, and revocation-endpoint constructors.
"""
self.credentials_grant = ClientCredentialsGrant(request_validator)
self.bearer = BearerToken(request_validator, token_generator,
token_expires_in, refresh_token_generator)
TokenEndpoint.__init__(self, default_grant_type='client_credentials',
grant_types={
'client_credentials': self.credentials_grant},
default_token_type=self.bearer)
ResourceEndpoint.__init__(self, default_token='Bearer',
token_types={'Bearer': self.bearer})
RevocationEndpoint.__init__(self, request_validator,
supported_token_types=['access_token'])
IntrospectEndpoint.__init__(self, request_validator,
supported_token_types=['access_token'])
self.bearer = BearerToken(
request_validator, token_generator, token_expires_in, refresh_token_generator
)
TokenEndpoint.__init__(
self,
default_grant_type="client_credentials",
grant_types={"client_credentials": self.credentials_grant},
default_token_type=self.bearer,
)
ResourceEndpoint.__init__(
self, default_token="Bearer", token_types={"Bearer": self.bearer}
)
RevocationEndpoint.__init__(
self, request_validator, supported_token_types=["access_token"]
)
IntrospectEndpoint.__init__(
self, request_validator, supported_token_types=["access_token"]
)
5 changes: 5 additions & 0 deletions oauthlib/oauth2/rfc8628/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
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__)
Loading
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy