Skip to content

Commit 83e2d19

Browse files
authored
Pass in type user_token in props during oauth flow (cloudflare#184)
1 parent 2621557 commit 83e2d19

File tree

3 files changed

+21
-5
lines changed

3 files changed

+21
-5
lines changed

.changeset/shaggy-llamas-shop.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@repo/mcp-common': patch
3+
---
4+
5+
Pass in type user_token in props during oauth flow

apps/sandbox-container/server/containerManager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ export class ContainerManager extends DurableObject<Env> {
4040

4141
// 15m timeout for container lifetime
4242
if (now.valueOf() - time.valueOf() > 15 * 60 * 1000) {
43+
await this.killContainer(id)
44+
// TODO: Figure out why we were running in to invalid durable object id the id does not match this durable object class error
4345
const doId = this.env.USER_CONTAINER.idFromString(id)
4446
const stub = this.env.USER_CONTAINER.get(doId)
4547
await stub.destroyContainer()
46-
await this.killContainer(id)
4748
}
4849
}
4950
}

packages/mcp-common/src/cloudflare-oauth-handler.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ const UserAuthProps = z.object({
6868
accessToken: z.string(),
6969
user: UserSchema,
7070
accounts: AccountsSchema,
71+
refreshToken: z.string().optional(),
7172
})
7273
export type AuthProps = z.infer<typeof AuthProps>
7374
const AuthProps = z.discriminatedUnion('type', [AccountAuthProps, UserAuthProps])
@@ -153,6 +154,15 @@ export async function handleTokenExchangeCallback(
153154
): Promise<TokenExchangeCallbackResult | undefined> {
154155
// options.props contains the current props
155156
if (options.grantType === 'refresh_token') {
157+
const props = AuthProps.parse(options.props)
158+
if (props.type === 'account_token') {
159+
// Refreshing an account_token should not be possible, as we only do this for user tokens
160+
throw new McpError('Internal Server Error', 500)
161+
}
162+
if (!props.refreshToken) {
163+
throw new McpError('Missing refreshToken', 500)
164+
}
165+
156166
// handle token refreshes
157167
const {
158168
access_token: accessToken,
@@ -161,15 +171,15 @@ export async function handleTokenExchangeCallback(
161171
} = await refreshAuthToken({
162172
client_id: clientId,
163173
client_secret: clientSecret,
164-
refresh_token: options.props.refreshToken,
174+
refresh_token: props.refreshToken,
165175
})
166176

167177
return {
168178
newProps: {
169179
...options.props,
170180
accessToken,
171181
refreshToken,
172-
},
182+
} satisfies AuthProps,
173183
accessTokenTTL: expires_in,
174184
}
175185
}
@@ -279,13 +289,13 @@ export function createAuthHandlers({
279289
label: user.email,
280290
},
281291
scope: oauthReqInfo.scope,
282-
// This will be available on this.props inside CASBMCP
283292
props: {
293+
type: 'user_token',
284294
user,
285295
accounts,
286296
accessToken,
287297
refreshToken,
288-
},
298+
} satisfies AuthProps,
289299
})
290300

291301
metrics.logEvent(

0 commit comments

Comments
 (0)