Skip to content

Commit ed534dd

Browse files
btiernayclaude
andcommitted
fix: address PR feedback - improve error messages and timeout consistency
- Add timeout configuration to get_access_token_for_connection for consistency - Improve Content-Type parsing with explicit comments for lenient JSON detection - Enhance unsupported type error messages to explain allowed types - Clarify case-insensitive Bearer prefix check in error message and docs - Fix docstring example to use async function context (avoid 'await outside async' warning) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 49e003e commit ed534dd

File tree

2 files changed

+11
-7
lines changed

2 files changed

+11
-7
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ asyncio.run(main())
166166

167167
**Important:**
168168
- Client authentication is sent via HTTP Basic (`client_id`/`client_secret`), not in the form body.
169-
- Do not prefix `subject_token` with "Bearer " - send the raw token value only.
169+
- Do not prefix `subject_token` with "Bearer " - send the raw token value only (checked case-insensitively).
170170
- The `subject_token_type` must match a Token Exchange Profile configured in Auth0. This URI identifies which profile will process the exchange and **must not use reserved OAuth namespaces (IETF or vendor-controlled)**. Use your own collision-resistant namespace. See the [Custom Token Exchange documentation](https://auth0.com/docs/authenticate/custom-token-exchange) for naming guidance.
171171
- If neither an explicit `audience` nor tenant/Action logic sets it, you may receive a token not targeted at your API.
172172

src/auth0_api_python/api_client.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,16 +471,17 @@ async def get_access_token_for_connection(self, options: dict[str, Any]) -> dict
471471
params["login_hint"] = options["login_hint"]
472472

473473
try:
474-
async with httpx.AsyncClient() as client:
474+
async with httpx.AsyncClient(timeout=httpx.Timeout(self.options.timeout)) as client:
475475
response = await client.post(
476476
token_endpoint,
477477
data=params,
478478
auth=(client_id, client_secret)
479479
)
480480

481481
if response.status_code != 200:
482-
error_data = response.json() if "json" in response.headers.get(
483-
"content-type", "").lower() else {}
482+
# Lenient check for JSON error responses (handles application/json, text/json, etc.)
483+
content_type = response.headers.get("content-type", "").lower()
484+
error_data = response.json() if "json" in content_type else {}
484485
raise ApiError(
485486
error_data.get("error", "connection_token_error"),
486487
error_data.get(
@@ -596,7 +597,7 @@ async def example():
596597
)
597598
if tok.lower().startswith("bearer "):
598599
raise GetTokenByExchangeProfileError(
599-
"subject_token must not include the 'Bearer ' prefix"
600+
"subject_token must not include the 'Bearer ' prefix (case-insensitive check)"
600601
)
601602

602603
# Require client credentials
@@ -649,7 +650,9 @@ async def example():
649650
if response.status_code != 200:
650651
error_data = {}
651652
try:
652-
if "json" in response.headers.get("content-type", "").lower():
653+
# Lenient check for JSON error responses (handles application/json, text/json, etc.)
654+
content_type = response.headers.get("content-type", "").lower()
655+
if "json" in content_type:
653656
error_data = response.json()
654657
except ValueError:
655658
pass # Ignore JSON parse errors, use generic error message below
@@ -751,7 +754,8 @@ def _apply_extra(
751754
# Handle sequences (list, tuple, etc.) but reject mappings/sets/bytes
752755
if isinstance(v, (dict, set, bytes)):
753756
raise GetTokenByExchangeProfileError(
754-
f"Parameter '{k}' has unsupported type {type(v).__name__}"
757+
f"Parameter '{k}' has unsupported type {type(v).__name__}. "
758+
"Only strings, numbers, booleans, and sequences (list/tuple) are allowed"
755759
)
756760
elif isinstance(v, (list, tuple)):
757761
if len(v) > MAX_ARRAY_VALUES_PER_KEY:

0 commit comments

Comments
 (0)