diff --git a/.changeset/shaggy-llamas-shop.md b/.changeset/shaggy-llamas-shop.md new file mode 100644 index 00000000..94195a25 --- /dev/null +++ b/.changeset/shaggy-llamas-shop.md @@ -0,0 +1,5 @@ +--- +'@repo/mcp-common': patch +--- + +Pass in type user_token in props during oauth flow diff --git a/apps/sandbox-container/server/containerManager.ts b/apps/sandbox-container/server/containerManager.ts index 676d1cfa..ca6c9196 100644 --- a/apps/sandbox-container/server/containerManager.ts +++ b/apps/sandbox-container/server/containerManager.ts @@ -40,10 +40,11 @@ export class ContainerManager extends DurableObject { // 15m timeout for container lifetime if (now.valueOf() - time.valueOf() > 15 * 60 * 1000) { + await this.killContainer(id) + // TODO: Figure out why we were running in to invalid durable object id the id does not match this durable object class error const doId = this.env.USER_CONTAINER.idFromString(id) const stub = this.env.USER_CONTAINER.get(doId) await stub.destroyContainer() - await this.killContainer(id) } } } diff --git a/packages/mcp-common/src/cloudflare-oauth-handler.ts b/packages/mcp-common/src/cloudflare-oauth-handler.ts index f92ef5c1..241a97e2 100644 --- a/packages/mcp-common/src/cloudflare-oauth-handler.ts +++ b/packages/mcp-common/src/cloudflare-oauth-handler.ts @@ -68,6 +68,7 @@ const UserAuthProps = z.object({ accessToken: z.string(), user: UserSchema, accounts: AccountsSchema, + refreshToken: z.string().optional(), }) export type AuthProps = z.infer const AuthProps = z.discriminatedUnion('type', [AccountAuthProps, UserAuthProps]) @@ -153,6 +154,15 @@ export async function handleTokenExchangeCallback( ): Promise { // options.props contains the current props if (options.grantType === 'refresh_token') { + const props = AuthProps.parse(options.props) + if (props.type === 'account_token') { + // Refreshing an account_token should not be possible, as we only do this for user tokens + throw new McpError('Internal Server Error', 500) + } + if (!props.refreshToken) { + throw new McpError('Missing refreshToken', 500) + } + // handle token refreshes const { access_token: accessToken, @@ -161,7 +171,7 @@ export async function handleTokenExchangeCallback( } = await refreshAuthToken({ client_id: clientId, client_secret: clientSecret, - refresh_token: options.props.refreshToken, + refresh_token: props.refreshToken, }) return { @@ -169,7 +179,7 @@ export async function handleTokenExchangeCallback( ...options.props, accessToken, refreshToken, - }, + } satisfies AuthProps, accessTokenTTL: expires_in, } } @@ -279,13 +289,13 @@ export function createAuthHandlers({ label: user.email, }, scope: oauthReqInfo.scope, - // This will be available on this.props inside CASBMCP props: { + type: 'user_token', user, accounts, accessToken, refreshToken, - }, + } satisfies AuthProps, }) metrics.logEvent(