11from __future__ import annotations
2+
23import base64
3- from datetime import timedelta
44import logging
55import time
6- from typing import Optional , TYPE_CHECKING , Union
76import uuid
7+ from datetime import timedelta
8+ from typing import Optional , TYPE_CHECKING , Union
9+
810import httpx
911
1012from ably .types .options import Options
13+
1114if TYPE_CHECKING :
1215 from ably .rest .rest import AblyRest
1316 from ably .realtime .realtime import AblyRealtime
1619from ably .types .tokendetails import TokenDetails
1720from ably .types .tokenrequest import TokenRequest
1821from ably .util .exceptions import AblyAuthException , AblyException , IncompatibleClientIdException
22+ from ably .util .helper import extract_url_params
1923
2024__all__ = ["Auth" ]
2125
2226log = logging .getLogger (__name__ )
2327
2428
2529class Auth :
26-
2730 class Method :
2831 BASIC = "BASIC"
2932 TOKEN = "TOKEN"
@@ -271,8 +274,7 @@ async def create_token_request(self, token_params: Optional[dict | str] = None,
271274 if capability is not None :
272275 token_request ['capability' ] = str (Capability (capability ))
273276
274- token_request ["client_id" ] = (
275- token_params .get ('client_id' ) or self .client_id )
277+ token_request ["client_id" ] = token_params .get ('client_id' ) or self .client_id
276278
277279 # Note: There is no expectation that the client
278280 # specifies the nonce; this is done by the library
@@ -388,17 +390,27 @@ def _random_nonce(self):
388390
389391 async def token_request_from_auth_url (self , method : str , url : str , token_params ,
390392 headers , auth_params ):
393+ # Extract URL parameters using utility function
394+ clean_url , url_params = extract_url_params (url )
395+
391396 body = None
392397 params = None
393398 if method == 'GET' :
394399 body = {}
395- params = dict (auth_params , ** token_params )
400+ # Merge URL params, auth_params, and token_params (later params override earlier ones)
401+ # we do this because httpx version has inconsistency and some versions override query params
402+ # that are specified in url string
403+ params = {** url_params , ** auth_params , ** token_params }
396404 elif method == 'POST' :
397405 if isinstance (auth_params , TokenDetails ):
398406 auth_params = auth_params .to_dict ()
399- params = {}
407+ # For POST, URL params go in query string, auth_params and token_params go in body
408+ params = url_params
400409 body = dict (auth_params , ** token_params )
401410
411+ # Use clean URL for the request
412+ url = clean_url
413+
402414 from ably .http .http import Response
403415 async with httpx .AsyncClient (http2 = True ) as client :
404416 resp = await client .request (method = method , url = url , headers = headers , params = params , data = body )
@@ -420,6 +432,6 @@ async def token_request_from_auth_url(self, method: str, url: str, token_params,
420432 token_request = response .text
421433 else :
422434 msg = 'auth_url responded with unacceptable content-type ' + content_type + \
423- ', should be either text/plain, application/jwt or application/json' ,
435+ ', should be either text/plain, application/jwt or application/json' ,
424436 raise AblyAuthException (msg , 401 , 40170 )
425437 return token_request
0 commit comments