Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion epicshop/epic-me/app/routes/oauth/authorize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,17 @@ export async function action({ request, context }: Route.ActionArgs) {
Object.fromEntries(url.searchParams),
)

// Strip `resource` from the request — the MCP client sends its own URL
// (e.g. http://localhost:56000/mcp) as the resource, but API calls go to
// a different host (the Worker). Storing that as the token audience would
// cause a permanent mismatch on every /db-api call. With no audience set,
// the library skips audience validation entirely.
const { resource: _ignored, ...requestWithoutResource } = requestParams as
typeof requestParams & { resource?: string }

const { redirectTo } =
await context.cloudflare.env.OAUTH_PROVIDER.completeAuthorization({
request: requestParams,
request: requestWithoutResource,
userId: String(user.id),
metadata: {
label: user.email,
Expand Down
3 changes: 2 additions & 1 deletion epicshop/epic-me/workers/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ async function stripResourceFromTokenRequest(request: Request): Promise<Request>
const contentType = request.headers.get('content-type') ?? ''
if (!contentType.includes('application/x-www-form-urlencoded')) return request

const body = await request.text()
// Read from a clone so the original request body stays available.
const body = await request.clone().text()
const params = new URLSearchParams(body)
if (!params.has('resource')) return request

Expand Down