Skip to content

Commit fff6e56

Browse files
authored
Merge pull request #9 from cloudflare/kenton/access-token-callback
Add access token exchange callback
2 parents c364360 + b0fe6dd commit fff6e56

File tree

5 files changed

+1200
-19
lines changed

5 files changed

+1200
-19
lines changed

.github/workflows/tests.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Setup Node.js
17+
uses: actions/setup-node@v4
18+
with:
19+
node-version: 20
20+
cache: 'npm'
21+
22+
- name: Install dependencies
23+
run: npm ci
24+
25+
- name: Run tests
26+
run: npm test

README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,72 @@ 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+
accessTokenProps: {
222+
...options.props,
223+
upstreamAccessToken: upstreamTokens.access_token
224+
},
225+
// Update the props stored in the grant (for future token refreshes)
226+
newProps: {
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+
accessTokenProps: {
239+
...options.props,
240+
upstreamAccessToken: upstreamTokens.access_token
241+
},
242+
newProps: {
243+
...options.props,
244+
upstreamRefreshToken: upstreamTokens.refresh_token || options.props.upstreamRefreshToken
245+
},
246+
// Optionally override the default access token TTL to match the upstream token
247+
accessTokenTTL: upstreamTokens.expires_in
248+
};
249+
}
250+
}
251+
});
252+
```
253+
254+
The callback can:
255+
- Return both `accessTokenProps` and `newProps` to update both
256+
- Return only `accessTokenProps` to update just the current access token
257+
- Return only `newProps` to update both the grant and access token (the access token inherits these props)
258+
- Return `accessTokenTTL` to override the default TTL for this specific access token
259+
- Return nothing to keep the original props unchanged
260+
261+
The `accessTokenTTL` override is particularly useful when the application is also an OAuth client to another service and wants to match its access token TTL to the upstream access token TTL. This helps prevent situations where the downstream token is still valid but the upstream token has expired.
262+
263+
The `props` values are end-to-end encrypted, so they can safely contain sensitive information.
264+
199265
## Written by Claude
200266

201267
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)