Feature Request: Support async onAuthUrl callback in withAccessToken
Is your feature request related to a problem? Please describe.
When using withAccessToken with USER_FEDERATION (3LO) flow in a streaming agent, there's no clean way to send the OAuth authorization URL to the client before polling starts.
Currently, onAuthUrl fires synchronously and polling begins immediately:
const fetchWithAuth = withAccessToken({
onAuthUrl: (url) => {
// This fires, then SDK immediately starts polling
// In an async generator, we can't "yield" from inside a callback
console.log('Auth URL:', url) // Only option is logging
},
})(myFunction)
In SSE streaming contexts (like BedrockAgentCoreApp handlers), we need to yield the auth URL to the client as an event. But we can't yield from inside a callback — by the time control returns to our async generator, polling has already started.
Describe the solution you'd like
Allow onAuthUrl to be an async function that the SDK awaits before starting to poll:
const fetchWithAuth = withAccessToken({
providerName: 'google',
authFlow: 'USER_FEDERATION',
onAuthUrl: async (url) => {
// SDK awaits this BEFORE starting to poll
await sendAuthUrlToClient(url)
},
})(myFunction)
This gives developers control over when polling starts, ensuring the client receives the auth URL first.
Proposed API
import { withAccessToken } from 'bedrock-agentcore/identity'
const fetchCalendarWithAuth = withAccessToken({
providerName: 'google-cal-provider',
scopes: ['https://www.googleapis.com/auth/calendar.readonly'],
authFlow: 'USER_FEDERATION',
callbackUrl: 'http://localhost:9090/oauth2/callback',
// NEW: SDK awaits this before polling starts
onAuthUrl: async (url) => {
// Developer can now do async work before polling begins
await emitToStream({ type: 'auth_url', url })
},
})(async (token) => {
return fetch('https://googleapis.com/calendar/v3/...', {
headers: { Authorization: `Bearer ${token}` },
})
})
Describe alternatives you've considered
We implemented a workaround using a signal pattern with Promise.race:
function createAuthSignal() {
let resolve: ((url: string) => void) | null = null
let promise = new Promise<string>((r) => { resolve = r })
return {
emit(url: string) {
resolve?.(url)
promise = new Promise<string>((r) => { resolve = r })
},
wait() { return promise },
}
}
const authSignal = createAuthSignal()
// onAuthUrl emits to signal
onAuthUrl: (url) => authSignal.emit(url)
// Handler races between agent stream and auth signal
const result = await Promise.race([
stream.next().then((r) => ({ type: 'stream', ...r })),
authSignal.wait().then((url) => ({ type: 'auth', url })),
])
if (result.type === 'auth') {
yield { event: 'auth_url', data: { authUrl: result.url } }
}
This works but requires manual orchestration that could be avoided with async onAuthUrl support.
Use Case
Building agents with BedrockAgentCoreApp that access user resources via 3LO OAuth (Google Calendar, Slack, etc.) while streaming responses to the client.
The flow:
- User asks "What's on my calendar?"
- Agent calls tool →
withAccessToken needs authorization
- Auth URL should be yielded to client immediately so user can authorize
- After user authorizes, polling completes and agent continues
Without async onAuthUrl, step 3 requires complex workarounds.
Additional context
Example from our Google Calendar sample showing the full streaming handler with workaround:
// agent.ts
const authSignal = createAuthSignal()
const fetchCalendarEvents = withAccessToken({
providerName: PROVIDER_NAME,
authFlow: 'USER_FEDERATION',
onAuthUrl: (url) => authSignal.emit(url),
})(async (maxResults: number, token: string) => {
// fetch calendar data
})
const app = new BedrockAgentCoreApp({
invocationHandler: {
process: async function* (request, context) {
const stream = agent.stream(request.prompt)[Symbol.asyncIterator]()
while (true) {
const result = await Promise.race([
stream.next().then((r) => ({ type: 'stream' as const, ...r })),
authSignal.wait().then((url) => ({ type: 'auth' as const, url })),
])
if (result.type === 'auth') {
yield { event: 'auth_url', data: { authUrl: result.url } }
continue
}
if (result.done) break
// yield other events...
}
},
},
})
With async onAuthUrl, this simplifies significantly.
Would you be willing to contribute this feature?
Feature Request: Support async
onAuthUrlcallback inwithAccessTokenIs your feature request related to a problem? Please describe.
When using
withAccessTokenwithUSER_FEDERATION(3LO) flow in a streaming agent, there's no clean way to send the OAuth authorization URL to the client before polling starts.Currently,
onAuthUrlfires synchronously and polling begins immediately:In SSE streaming contexts (like
BedrockAgentCoreApphandlers), we need to yield the auth URL to the client as an event. But we can't yield from inside a callback — by the time control returns to our async generator, polling has already started.Describe the solution you'd like
Allow
onAuthUrlto be an async function that the SDK awaits before starting to poll:This gives developers control over when polling starts, ensuring the client receives the auth URL first.
Proposed API
Describe alternatives you've considered
We implemented a workaround using a signal pattern with
Promise.race:This works but requires manual orchestration that could be avoided with async
onAuthUrlsupport.Use Case
Building agents with
BedrockAgentCoreAppthat access user resources via 3LO OAuth (Google Calendar, Slack, etc.) while streaming responses to the client.The flow:
withAccessTokenneeds authorizationWithout async
onAuthUrl, step 3 requires complex workarounds.Additional context
Example from our Google Calendar sample showing the full streaming handler with workaround:
With async
onAuthUrl, this simplifies significantly.Would you be willing to contribute this feature?