@@ -976,7 +976,11 @@ async def test_client_registration_invalid_grant_type(self, test_client: httpx.A
976976 assert error_data ["error" ] == "invalid_client_metadata"
977977 assert (
978978 error_data ["error_description" ]
979- == "grant_types must be authorization_code and refresh_token or client_credentials or token exchange"
979+ == (
980+ "grant_types must be authorization_code and refresh_token "
981+ "or client_credentials or token exchange or "
982+ "client_credentials and token_exchange"
983+ )
980984 )
981985
982986 @pytest .mark .anyio
@@ -1336,3 +1340,33 @@ async def test_token_exchange_invalid_subject(self, test_client: httpx.AsyncClie
13361340 assert response .status_code == 400
13371341 data = response .json ()
13381342 assert data ["error" ] == "invalid_grant"
1343+
1344+ @pytest .mark .anyio
1345+ @pytest .mark .parametrize (
1346+ "registered_client" ,
1347+ [{"grant_types" : ["client_credentials" , "token_exchange" ]}],
1348+ indirect = True ,
1349+ )
1350+ async def test_client_credentials_and_token_exchange (self , test_client : httpx .AsyncClient , registered_client ):
1351+ cc_response = await test_client .post (
1352+ "/token" ,
1353+ data = {
1354+ "grant_type" : "client_credentials" ,
1355+ "client_id" : registered_client ["client_id" ],
1356+ "client_secret" : registered_client ["client_secret" ],
1357+ "scope" : "read write" ,
1358+ },
1359+ )
1360+ assert cc_response .status_code == 200
1361+
1362+ te_response = await test_client .post (
1363+ "/token" ,
1364+ data = {
1365+ "grant_type" : "token_exchange" ,
1366+ "client_id" : registered_client ["client_id" ],
1367+ "client_secret" : registered_client ["client_secret" ],
1368+ "subject_token" : "good_token" ,
1369+ "subject_token_type" : "access_token" ,
1370+ },
1371+ )
1372+ assert te_response .status_code == 200
0 commit comments