diff --git a/authlib/oauth2/rfc7592/endpoint.py b/authlib/oauth2/rfc7592/endpoint.py index cec9aad1..25d8b6ab 100644 --- a/authlib/oauth2/rfc7592/endpoint.py +++ b/authlib/oauth2/rfc7592/endpoint.py @@ -136,7 +136,10 @@ def _validate_scope(claims, value): response_types_supported = set(response_types_supported) def _validate_response_types(claims, value): - return response_types_supported.issuperset(set(value)) + # If omitted, the default is that the client will use only the "code" + # response type. + response_types = set(value) if value else {"code"} + return response_types_supported.issuperset(response_types) options['response_types'] = {'validate': _validate_response_types} @@ -144,7 +147,10 @@ def _validate_response_types(claims, value): grant_types_supported = set(grant_types_supported) def _validate_grant_types(claims, value): - return grant_types_supported.issuperset(set(value)) + # If omitted, the default behavior is that the client will use only + # the "authorization_code" Grant Type. + grant_types = set(value) if value else {"authorization_code"} + return grant_types_supported.issuperset(grant_types) options['grant_types'] = {'validate': _validate_grant_types} diff --git a/tests/flask/test_oauth2/test_client_configuration_endpoint.py b/tests/flask/test_oauth2/test_client_configuration_endpoint.py index 661a8f4b..0cc2da14 100644 --- a/tests/flask/test_oauth2/test_client_configuration_endpoint.py +++ b/tests/flask/test_oauth2/test_client_configuration_endpoint.py @@ -21,7 +21,7 @@ def authenticate_token(self, request): return Token.query.filter_by(access_token=access_token).first() def update_client(self, client, client_metadata, request): - client.set_client_metadata({**client.client_metadata, **client_metadata}) + client.set_client_metadata(client_metadata) db.session.add(client) db.session.commit() return client @@ -195,7 +195,7 @@ def test_update_client(self): self.assertEqual(resp['client_id'], client.client_id) self.assertEqual(resp['client_name'], 'NewAuthlib') self.assertEqual(client.client_name, 'NewAuthlib') - self.assertEqual(client.scope, 'openid profile') + self.assertEqual(client.scope, '') def test_access_denied(self): user, client, token = self.prepare_data() @@ -382,6 +382,16 @@ def test_response_types_supported(self): self.assertEqual(resp['client_name'], 'Authlib') self.assertEqual(resp['response_types'], ['code']) + # https://datatracker.ietf.org/doc/html/rfc7592#section-2.2 + # If omitted, the default is that the client will use only the "code" + # response type. + body = {'client_id': 'client_id', 'client_name': 'Authlib'} + rv = self.client.put('/configure_client/client_id', json=body, headers=headers) + resp = json.loads(rv.data) + self.assertIn('client_id', resp) + self.assertEqual(resp['client_name'], 'Authlib') + self.assertNotIn('response_types', resp) + body = { 'client_id': 'client_id', 'response_types': ['code', 'token'], @@ -407,6 +417,16 @@ def test_grant_types_supported(self): self.assertEqual(resp['client_name'], 'Authlib') self.assertEqual(resp['grant_types'], ['password']) + # https://datatracker.ietf.org/doc/html/rfc7592#section-2.2 + # If omitted, the default behavior is that the client will use only + # the "authorization_code" Grant Type. + body = {'client_id': 'client_id', 'client_name': 'Authlib'} + rv = self.client.put('/configure_client/client_id', json=body, headers=headers) + resp = json.loads(rv.data) + self.assertIn('client_id', resp) + self.assertEqual(resp['client_name'], 'Authlib') + self.assertNotIn('grant_types', resp) + body = { 'client_id': 'client_id', 'grant_types': ['client_credentials'],