aws / aws/bedrock-agentcore-sdk-python

[Bug] @requires_access_token not sending code_verifier in PKCE token exchange

Open
#158 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.