Skip to content

Commit 89ad47e

Browse files
committed
Ask Claude to implement a token exchange callback.
This lets the app specify a callback to invoke during token exchanges which can update the `props`. This is particularly useful when the application is itself is a client to some other OAuth API, and needs to perform upstream token refreshes. These can be tied to the downstream refreshes, which maintains the end-to-end encryption. Otherwise, the upstream tokens would need to be stored in some separate storage which may not be e2e. Full transcript: https://claude-workerd-transcript.pages.dev/oauth-provider-token-exchange-callback
1 parent 120476a commit 89ad47e

File tree

3 files changed

+830
-7
lines changed

3 files changed

+830
-7
lines changed

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,66 @@ The `env.OAUTH_PROVIDER` object available to the fetch handlers provides some me
196196

197197
See the `OAuthHelpers` interface definition for full API details.
198198

199+
## Token Exchange Callback
200+
201+
This library allows you to update the `props` value during token exchanges by configuring a callback function. This is useful for scenarios where the application needs to perform additional processing when tokens are issued or refreshed.
202+
203+
For example, if your application is also a client to some other OAuth API, you might want to perform an equivalent upstream token exchange and store the result in the `props`. The callback can be used to update the props for both the grant record and specific access tokens.
204+
205+
To use this feature, provide a `tokenExchangeCallback` in your OAuthProvider options:
206+
207+
```ts
208+
new OAuthProvider({
209+
// ... other options ...
210+
tokenExchangeCallback: async (options) => {
211+
// options.grantType is either 'authorization_code' or 'refresh_token'
212+
// options.props contains the current props
213+
// options.clientId, options.userId, and options.scope are also available
214+
215+
if (options.grantType === 'authorization_code') {
216+
// For authorization code exchange, might want to obtain upstream tokens
217+
const upstreamTokens = await exchangeUpstreamToken(options.props.someCode);
218+
219+
return {
220+
// Update the props stored in the access token
221+
tokenProps: {
222+
...options.props,
223+
upstreamAccessToken: upstreamTokens.access_token
224+
},
225+
// Update the props stored in the grant (for future token refreshes)
226+
grantProps: {
227+
...options.props,
228+
upstreamRefreshToken: upstreamTokens.refresh_token
229+
}
230+
};
231+
}
232+
233+
if (options.grantType === 'refresh_token') {
234+
// For refresh token exchanges, might want to refresh upstream tokens too
235+
const upstreamTokens = await refreshUpstreamToken(options.props.upstreamRefreshToken);
236+
237+
return {
238+
tokenProps: {
239+
...options.props,
240+
upstreamAccessToken: upstreamTokens.access_token
241+
},
242+
grantProps: {
243+
...options.props,
244+
upstreamRefreshToken: upstreamTokens.refresh_token || options.props.upstreamRefreshToken
245+
}
246+
};
247+
}
248+
}
249+
});
250+
```
251+
252+
The callback can:
253+
- Return both `tokenProps` and `grantProps` to update both
254+
- Return only `tokenProps` or `grantProps` to update just one
255+
- Return nothing to keep the original props unchanged
256+
257+
The `props` values are end-to-end encrypted, so they can safely contain sensitive information.
258+
199259
## Written by Claude
200260

201261
This library (including the schema documentation) was largely written by [Claude](https://claude.ai), the AI model by Anthropic. Claude's output was thoroughly reviewed by Cloudflare engineers with careful attention paid to security and compliance with standards. Many improvements were made on the initial output, mostly again by prompting Claude (and reviewing the results). Check out the commit history to see how Claude was prompted and what code it produced.

0 commit comments

Comments
 (0)