@@ -52,6 +52,15 @@ async def exchange_client_credentials(self, client_info: object, scopes: list[st
5252 raise TokenError (error = "invalid_client" , error_description = "bad credentials" )
5353
5454
55+ class ClientCredentialsProviderSuccess :
56+ def __init__ (self ) -> None :
57+ self .last_scopes : list [str ] | None = None
58+
59+ async def exchange_client_credentials (self , client_info : object , scopes : list [str ]) -> OAuthToken :
60+ self .last_scopes = scopes
61+ return OAuthToken (access_token = "client-token" )
62+
63+
5564class TokenExchangeProviderStub :
5665 def __init__ (self ) -> None :
5766 self .last_call : dict [str , Any ] | None = None
@@ -155,6 +164,67 @@ async def test_handle_client_credentials_returns_token_error() -> None:
155164 assert result .error_description == "bad credentials"
156165
157166
167+ @pytest .mark .anyio
168+ async def test_handle_route_authorization_code_branch () -> None :
169+ code_verifier = "a" * 64
170+ digest = hashlib .sha256 (code_verifier .encode ()).digest ()
171+ code_challenge = base64 .urlsafe_b64encode (digest ).decode ().rstrip ("=" )
172+
173+ provider = AuthorizationCodeProvider (expected_code = "auth-code" , code_challenge = code_challenge )
174+ client_info = OAuthClientInformationFull (
175+ client_id = "client" ,
176+ grant_types = ["authorization_code" ],
177+ scope = "alpha" ,
178+ )
179+ handler = TokenHandler (
180+ provider = cast (OAuthAuthorizationServerProvider [Any , Any , Any ], provider ),
181+ client_authenticator = cast (ClientAuthenticator , DummyAuthenticator (client_info )),
182+ )
183+
184+ request_data = {
185+ "grant_type" : "authorization_code" ,
186+ "code" : "auth-code" ,
187+ "redirect_uri" : None ,
188+ "client_id" : "client" ,
189+ "client_secret" : "secret" ,
190+ "code_verifier" : code_verifier ,
191+ }
192+
193+ response = await handler .handle (cast (Request , DummyRequest (request_data )))
194+
195+ assert response .status_code == 200
196+ payload = json .loads (bytes (response .body ).decode ())
197+ assert payload ["access_token" ] == "auth-token"
198+
199+
200+ @pytest .mark .anyio
201+ async def test_handle_route_client_credentials_branch () -> None :
202+ provider = ClientCredentialsProviderSuccess ()
203+ client_info = OAuthClientInformationFull (
204+ client_id = "client" ,
205+ grant_types = ["client_credentials" ],
206+ scope = "alpha beta" ,
207+ )
208+ handler = TokenHandler (
209+ provider = cast (OAuthAuthorizationServerProvider [Any , Any , Any ], provider ),
210+ client_authenticator = cast (ClientAuthenticator , DummyAuthenticator (client_info )),
211+ )
212+
213+ request_data = {
214+ "grant_type" : "client_credentials" ,
215+ "scope" : "beta" ,
216+ "client_id" : "client" ,
217+ "client_secret" : "secret" ,
218+ }
219+
220+ response = await handler .handle (cast (Request , DummyRequest (request_data )))
221+
222+ assert response .status_code == 200
223+ payload = json .loads (bytes (response .body ).decode ())
224+ assert payload ["access_token" ] == "client-token"
225+ assert provider .last_scopes == ["beta" ]
226+
227+
158228@pytest .mark .anyio
159229async def test_handle_route_refresh_token_branch () -> None :
160230 provider = RefreshTokenProvider ()
0 commit comments