api-token-mode.ts•2.17 kB
import { getUserAndAccounts } from './cloudflare-oauth-handler'
import type { McpAgent } from 'agents/mcp'
import type { AuthProps } from './cloudflare-oauth-handler'
interface RequiredEnv {
DEV_CLOUDFLARE_API_TOKEN: string
DEV_CLOUDFLARE_EMAIL: string
DEV_DISABLE_OAUTH: string
}
export async function isApiTokenRequest(req: Request, env: RequiredEnv) {
// shortcircuit for dev
if (env.DEV_CLOUDFLARE_API_TOKEN && env.DEV_DISABLE_OAUTH === 'true') {
return true
}
const authHeader = req.headers.get('Authorization')
if (!authHeader) return false
const [type, token] = authHeader.split(' ')
if (type !== 'Bearer') return false
// Return true only if the token was issued by the OAuthProvider.
// A token provisioned by the OAuthProvider has 3 parts, split by colons.
const codeParts = token.split(':')
return codeParts.length !== 3
}
export async function handleApiTokenMode<
T extends typeof McpAgent<unknown, unknown, Record<string, unknown>>,
>(agent: T, req: Request, env: RequiredEnv, ctx: ExecutionContext) {
// Handle global API token case
let opts, token
// dev mode
if (env.DEV_CLOUDFLARE_API_TOKEN && env.DEV_DISABLE_OAUTH === 'true') {
opts = {
Authorization: `Bearer ${env.DEV_CLOUDFLARE_API_TOKEN}`,
}
token = env.DEV_CLOUDFLARE_API_TOKEN
// header mode
} else {
const authHeader = req.headers.get('Authorization')
if (!authHeader) {
throw new Error('Authorization header is required')
}
const [type, tokenStr] = authHeader.split(' ')
if (type !== 'Bearer') {
throw new Error('Invalid authorization type, must be Bearer')
}
token = tokenStr
}
const { user, accounts } = await getUserAndAccounts(token, opts)
// If user is null, handle API token mode
if (user === null) {
ctx.props = {
type: 'account_token',
accessToken: token,
// we always select the first account from the response,
// this assumes that account owned tokens can only access one account
account: accounts[0],
} satisfies AuthProps
} else {
ctx.props = {
type: 'user_token',
accessToken: token,
user,
accounts,
} satisfies AuthProps
}
return agent.serve('/mcp').fetch(req, env, ctx)
}