RFC7592: OAuth 2.0 Dynamic Client Registration Management Protocol

This section contains the generic implementation of RFC 7592. OAuth 2.0 Dynamic Client Registration Management Protocol allows developers edit and delete OAuth client via API through Authorization Server. This specification is an extension of RFC7591: OAuth 2.0 Dynamic Client Registration Protocol.

Client Configuration Endpoint

The endpoint URL identifies the client, for instance /oauth/register/<client_id>. The registration access token returned by the RFC7591: OAuth 2.0 Dynamic Client Registration Protocol registration endpoint is only valid for this client. The endpoint calls check_client() on the token, and denies the request when the token was issued to another client.

Before register the endpoint, developers MUST implement the missing methods:

from urllib.parse import urlparse

from authlib.oauth2.rfc7592 import ClientConfigurationEndpoint


class MyClientConfigurationEndpoint(ClientConfigurationEndpoint):
    def authenticate_token(self, request):
        # this method is used to authenticate the registration access
        # token returned by the RFC7591 registration endpoint
        auth_header = request.headers.get('Authorization')
        bearer_token = auth_header.split()[1]
        token = Token.get(bearer_token)
        return token

    def authenticate_client(self, request):
        # read the client_id from the endpoint URL, not from the body:
        # GET and DELETE requests have no body.
        # The route parameter of the web framework can also be used.
        path = urlparse(request.uri).path
        client_id = path.rstrip('/').rsplit('/', 1)[-1]
        return Client.get(client_id=client_id)

    def revoke_access_token(self, token, request):
        token.revoked = True
        token.save()

    def check_permission(self, client, request):
        return client.editable

    def delete_client(self, client, request):
        client.delete()

    def update_client(self, client, client_metadata, request):
        client.set_client_metadata(client_metadata)
        client.save()
        return client

    def generate_client_registration_info(self, client, request):
        access_token = request.headers['Authorization'].split(' ')[1]
        return {
            'registration_client_uri': request.uri,
            'registration_access_token': access_token,
        }

    def get_server_metadata(self):
        return {
            'issuer': ...,
            'authorization_endpoint': ...,
            'token_endpoint': ...,
            'jwks_uri': ...,
            'registration_endpoint': ...,
            'scopes_supported': ...,
            'response_types_supported': ...,
            'response_modes_supported': ...,
            'grant_types_supported': ...,
            'token_endpoint_auth_methods_supported': ...,
            'token_endpoint_auth_signing_alg_values_supported': ...,
            'service_documentation': ...,
            'ui_locales_supported': ...,
            'op_policy_uri': ...,
            'op_tos_uri': ...,
            'revocation_endpoint': ...,
            'revocation_endpoint_auth_methods_supported': ...,
            'revocation_endpoint_auth_signing_alg_values_supported': ...,
            'introspection_endpoint': ...,
            'introspection_endpoint_auth_methods_supported': ...,
            'introspection_endpoint_auth_signing_alg_values_supported': ...,
            'code_challenge_methods_supported': ...,
        }

API Reference

class authlib.oauth2.rfc7592.ClientConfigurationEndpoint(server=None, claims_classes=None)
generate_client_registration_info(client, request)

Generate `registration_client_uri and registration_access_token for RFC7592. By default this method returns the values sent in the current request. Developers MUST rewrite this method to return different registration information.:

def generate_client_registration_info(self, client, request):{
    access_token = request.headers['Authorization'].split(' ')[1]
    return {
        'registration_client_uri': request.uri,
        'registration_access_token': access_token,
    }
Parameters:
  • client – the instance of OAuth client

  • request – formatted request instance

authenticate_token(request)

Authenticate the registration access token of the request. Developers MUST implement this method in subclass:

def authenticate_token(self, request):
    auth = request.headers.get("Authorization")
    return get_token_by_auth(auth)

The token MUST implement check_client(). Requests are denied when the token was not issued to the requested client.

Returns:

token instance

authenticate_client(request)

Read the client from the client configuration endpoint URL. Developers MUST implement this method in subclass:

from urllib.parse import urlparse


def authenticate_client(self, request):
    path = urlparse(request.uri).path
    client_id = path.rstrip("/").rsplit("/", 1)[-1]
    return Client.get(client_id=client_id)

The route parameter of the web framework can also be used.

Returns:

client instance

revoke_access_token(token, request)

Revoke a token access in case an invalid client has been requested. Developers MUST implement this method in subclass:

def revoke_access_token(self, token, request):
    token.revoked = True
    token.save()
check_permission(client, request)

Checks whether the current client is allowed to be accessed, edited or deleted. Developers MUST implement it in subclass, e.g.:

def check_permission(self, client, request):
    return client.editable
Returns:

boolean

delete_client(client, request)

Delete authorization code from database or cache. Developers MUST implement it in subclass, e.g.:

def delete_client(self, client, request):
    client.delete()
Parameters:
  • client – the instance of OAuth client

  • request – formatted request instance

update_client(client, client_metadata, request)

Update the client in the database. Developers MUST implement this method in subclass:

def update_client(self, client, client_metadata, request):
    client.set_client_metadata(
        {**client.client_metadata, **client_metadata}
    )
    client.save()
    return client
Parameters:
  • client – the instance of OAuth client

  • client_metadata – a dict of the client claims to update

  • request – formatted request instance

Returns:

client instance

get_server_metadata()

Return server metadata which includes supported grant types, response types and etc.