aws / aws/bedrock-agentcore-sdk-python
[Bug] @requires_access_token not sending code_verifier in PKCE token exchange
- Dominant language
- Python
- Stars
- 761
- Forks
- 147
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 7
Description
### Description
The `@requires_access_token` decorator from `bedrock_agentcore.identity` correctly sends PKCE parameters (`code_challenge` + `code_challenge_method`) during OAuth authorization but **fails to send the corresponding `code_verifier`** when exchanging the authorization code for tokens.
This causes token exchange to fail with OAuth providers that require PKCE (e.g., MercadoLibre API), preventing AgentCore Identity from working with these providers.
### Environment
- **Package**: `bedrock-agentcore` (Python SDK)
- **Version**: Latest (as of 2025-01-11)
- **Region**: us-west-2
- **OAuth Provider**: MercadoLibre API (custom OAuth2 provider with PKCE)
- **Decorator**: `@requires_access_token`
- **Auth Flow**: `USER_FEDERATION`
### Minimal Reproducible Example
```python
from bedrock_agentcore.identity import requires_access_token
import asyncio
@requires_access_token(
provider_name="mercadolibre-test",
scopes=["offline_access", "read", "write"],
auth_flow="USER_FEDERATION",
on_auth_url=lambda url: print(url),
callback_url="https://bedrock-agentcore.us-west-2.amazonaws.com/identities/oauth2/callback/{id}",
force_authentication=True
)
async def test_call(*, access_token: str):
print(f"Token: {access_token}")
return {"token": access_token}
asyncio.run(test_call())
```
**Provider Configuration**:
```python
import boto3
client = boto3.client('bedrock-agentcore-control', region_name='us-west-2')
client.create_oauth2_credential_provider(
name='mercadolibre-test',
credentialProviderVendor='CustomOauth2',
oauth2ProviderConfigInput={
'customOauth2ProviderConfig': {
'oauthDiscovery': {
'authorizationServerMetadata': {
'issuer': 'https://api.mercadolibre.com',
'authorizationEndpoint': 'https://auth.mercadolibre.com.mx/authorization',
'tokenEndpoint': 'https://api.mercadolibre.com/oauth/token',
'responseTypes': ['code']
}
},
'clientId': 'YOUR_CLIENT_ID',
'clientSecret': 'YOUR_CLIENT_SECRET'
}
}
)
```
### Expected Behavior
After user authenticates, the SDK should exchange the authorization code for tokens by sending:
```http
POST https://api.mercadolibre.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=TG-xxxxx
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&redirect_uri=CALLBACK_URL
&code_verifier=XXXXX ⬅️ REQUIRED when code_challenge was sent
```
User should receive access token and the decorator should inject it into the function.
### Actual Behavior
**Step 1 - Authorization (CORRECT)** ✅:
The SDK generates authorization URL with PKCE parameters:
```
https://auth.mercadolibre.com.mx/authorization?
client_id=6414553207646485
&redirect_uri=https://bedrock-agentcore.us-west-2.amazonaws.com/identities/oauth2/callback/c3e4cb15-4049-4f7c-97a6-73ab246f465c
&response_type=code
&scope=offline_access+read+write
&state=4ed283e8-c515-4191-a305-e6774a3e54e9
&code_challenge=0ElyxSEFV5g66D7K8R-xNBAI18tjrhqKK9HFjffGlgE
&code_challenge_method=S256
```
**Step 2 - User Authentication (CORRECT)** ✅:
User completes authentication in OAuth provider.
**Step 3 - OAuth Callback (CORRECT)** ✅:
OAuth provider redirects with valid code and state:
```
https://bedrock-agentcore.us-west-2.amazonaws.com/identities/oauth2/callback/c3e4cb15-4049-4f7c-97a6-73ab246f465c?
code=TG-69140f4cd6507c0001c6a29b-229455957
&state=4ed283e8-c515-4191-a305-e6774a3e54e9
```
**Step 4 - Internal Redirect (BUG)** ❌:
AgentCore performs a **302 redirect** that discards the OAuth parameters:
```
HTTP/1.1 302 Found
Location: https://bedrock-agentcore.us-west-2.amazonaws.com/identities/oauth2/callback/c3e4cb15-4049-4f7c-97a6-73ab246f465c?
session_id=urn:ietf:params:oauth:request_uri:NGVkMjgzZTgtYzUxNS00MTkxLWEzMDUtZTY3NzRhM2U1NGU5
```
**Step 5 - Error Page** ❌:
Browser shows:
```json
{
"message": "2 validation errors detected: Value at 'authorizationCode' failed to satisfy constraint: Member must not be null; Value at 'state' failed to satisfy constraint: Member must not be null"
}
```
**Step 6 - Decorator Never Returns** ❌:
The `@requires_access_token` decorator continues polling indefinitely, never receiving the token.
### Root Cause
Based on network inspection and OAuth flow analysis:
1. ✅ SDK sends `code_challenge` during authorization (PKCE enabled)
2. ✅ OAuth provider generates authorization code **with PKCE requirement**
3. ❌ **SDK does NOT send `code_verifier`** when exchanging code for tokens
4. ❌ OAuth provider rejects token exchange (MercadoLibre requires `code_verifier` when `code_challenge` was used)
5. ❌ AgentCore redirects to error page instead of properly handling the token exchange error
### Evidence
**Network Trace** (Chrome DevTools):
- Authorization request includes PKCE parameters ✅
- Callback receives valid `code` and `state` ✅
- AgentCore redirects to error page with `session_id` ❌
**MercadoLibre Documentation**:
- PKCE is supported (optional but mandatory when `code_challenge` is sent)
- When `code_challenge` is sent, `code_verifier` MUST be included in token exchange
- Reference: https://developers.mercadolibre.com.mx/en_us/news/authentication-and-authorization
**Stack Overflow Evidence**:
- Others have encountered "code_verifier is required" errors with MercadoLibre: https://stackoverflow.com/questions/77082637/
### Impact
**Custom OAuth2 providers that enforce PKCE cannot be used with AgentCore Identity**, including:
- MercadoLibre API (all countries: MLM, MLA, MLB, etc.)
- Any OAuth provider that requires `code_verifier` when `code_challenge` is sent
- Potentially other e-commerce and marketplace APIs
### Workaround
None available in the SDK. Users must implement OAuth token management outside of AgentCore Identity.
### Suggested Fix
The SDK should:
1. **Store the `code_verifier`** associated with each `code_challenge` generated
2. **Include `code_verifier`** in the token exchange request body:
```python
token_data = {
'grant_type': 'authorization_code',
'code': authorization_code,
'client_id': client_id,
'client_secret': client_secret,
'redirect_uri': redirect_uri,
'code_verifier': stored_code_verifier # ⬅️ ADD THIS
}
```
3. **Properly handle token exchange errors** instead of redirecting to error page with `session_id`
### Related Issues
- **Similar PAR issue**: #111 (different problem - PAR compatibility)
- **Also reported in samples repo**: https://github.com/awslabs/amazon-bedrock-agentcore-samples/issues/620
### Additional Context
- AgentCore Identity is in **Preview** status
- This affects `@requires_access_token` decorator specifically
- Issue is in the token exchange step, not authorization
- Built-in providers (GitHub, Google) may not be affected (unclear if they use PKCE)
---
**Is this blocking your use case?** Yes, cannot use AgentCore Identity with MercadoLibre API.
```
Contributor guide
Assessment
This issue has not been assessed yet.