Skip to content
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

Cannot add scope to registration request #856

Open
christian-hawk opened this issue Apr 23, 2023 · 5 comments
Open

Cannot add scope to registration request #856

christian-hawk opened this issue Apr 23, 2023 · 5 comments

Comments

@christian-hawk
Copy link

I would like to add the scope param to my dynamic registration request. But I realized that oic does not allow it the way I'm trying. scope param is being ignored.

As register docstring states:

"""
        Register the client at an OP.

        :param url: The OPs registration endpoint
        :param registration_token: Initial Access Token for registration endpoint
        :param kwargs: parameters to the registration request
        :return:
        """

so, example:

op_url = 'https://my-op-url.com'
client = Client(client_authn_method=CLIENT_AUTHN_METHOD)
op_data = client.provider_config(op_url)
registration_args = {'redirect_uris': redirect_uris,
                             'response_types': ['code'],
                             'grant_types': ['authorization_code'],
                             'application_type': 'web',
                             'client_name': 'My own RP',
                             'token_endpoint_auth_method': 'client_secret_post',
                             'scope': 'openid' }
reg_info = client.register(op_data['registration_endpoint'], **registration_args)

And the scope param is not sent in request.

I checked req.parameters(), which gets me the following params:

['redirect_uris', 'response_types', 'grant_types', 'application_type', 'contacts', 'client_name', 
'logo_uri', 'client_uri', 'policy_uri', 'tos_uri', 'jwks', 'jwks_uri', 'sector_identifier_uri', 
'subject_type', 'id_token_signed_response_alg', 'id_token_encrypted_response_alg', 
'id_token_encrypted_response_enc', 'userinfo_signed_response_alg', 
'userinfo_encrypted_response_alg', 'userinfo_encrypted_response_enc', 
'request_object_signing_alg', 'request_object_encryption_alg', 
'request_object_encryption_enc', 'token_endpoint_auth_method', 
'token_endpoint_auth_signing_alg', 'default_max_age', 'require_auth_time', 
'default_acr_values', 'initiate_login_uri', 'request_uris', 'post_logout_redirect_uris', 
'frontchannel_logout_uri', 'frontchannel_logout_session_required', 
'backchannel_logout_uri', 'backchannel_logout_session_required']

It looks like any other param then not any of those, is ignored.

After researching OAuth docs, in RFC7591 Section 1.3 , I found the following:

The following client metadata fields are defined by this
specification. The implementation and use of all client metadata
fields is OPTIONAL, unless stated otherwise.

scope
String containing a space-separated list of scope values (as
described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client
can use when requesting access tokens. The semantics of values in
this list are service specific. If omitted, an authorization
server MAY register a client with a default set of scopes.

@schlenk
Copy link
Collaborator

schlenk commented Apr 23, 2023

Why do you think you need to register the scope for OpenID connect? Does some OP force that?

For OpenID Dynamic Registration (https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata ) scope isn't a supported value. So the default oic.oic.Client does not implement it.

OAuth 2.0 does allow it though, but we only implement the OAuth2 registration in the extensions, https://github.com/CZ-NIC/pyoidc/blob/444bd6845e13b06c14fbaefccbc0c47059aa2364/src/oic/extension/client.py#L390, see the RegistrationRequest class

class RegistrationRequest(Message):
this allows scope as part of the registration.

@christian-hawk
Copy link
Author

Why do you think you need to register the scope for OpenID connect? Does some OP force that?

It does not force, but it register with no scope at all.

For OpenID Dynamic Registration (https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata ) scope isn't a supported value. So the default oic.oic.Client does not implement it.

Actually scope is supported, but unlisted in this spec. If you check the last line of the provided section, you will find:


Additional Client Metadata parameters MAY also be used. Some are defined by other specifications, such as OpenID Connect Session Management 1.0 [OpenID.Session].


Another interesting reading for this topic can be found at OpenID Foundation repository, entitled "Update dynamic client registration spec to reference OAuth2 dynamic client reg". Issue description:

In section 2.0 (Client Metadata) of the Dynamic Client Registration spec there is a statement at the end of the section that says "Additional Client Metadata parameters MAY also be used. ..."
I recommend we update this text to also reference the OAuth2 Dynamic Client Registration spec as another place where additional client metadata parameters are defined (specifically, scope and software statements).
"Additional Client Metadata parameters MAY also be used. Some are defined by other specifications, such as OpenID Connect Session Management 1.0 [OpenID.Session] and OAuth 2.0 Dynamic Client Registration Protocol [https://tools.ietf.org/html/rfc7591]".

Correct me if I'm wrong, but by specs sending scope is allowed.

@schlenk
Copy link
Collaborator

schlenk commented Apr 25, 2023

Agreed. The spec allows sending any key and value you want.
The default client just does not implement arbitrary additional registration values in its message factory in order to be able to validate the parameters.

So if you want to register a scope value, you must override the message_factory passed into the client:

from oic.oic.message import OIDCMessageFactory, RegistrationRequest, RegistrationResponse, MessageTuple

class MyRegistrationRequest(RegistrationRequest):
    # add the fields you want to send

class MyRegistrationResponse(RegistrationResponse):
    # add the extra fields you expect the OP to send back

class MyMessageFactory(OIDCMessageFactory):
        registration_endpoint = MessageTuple(MyRegistrationRequest, MyRegistrationResponse)

client = Client(client_authn_method=CLIENT_AUTHN_METHOD,
                      message_factory=MyMessageFactory)

See the https://github.com/CZ-NIC/pyoidc/blob/master/src/oic/extension/message.py#L97 for a message type that has the OAuth2 registration fields available.
There are a lot of publicly registered fields, see https://www.iana.org/assignments/oauth-parameters/oauth-parameters.xhtml#client-metadata for the public list and any OP might invent their own additional ones.

@christian-hawk
Copy link
Author

thanks, do you think that updating docs / docstring about allowed fields may be helpful?

@tpazderka
Copy link
Collaborator

Yes, you are welcome to submit a PR with updated docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants