From 9568b975100cb8c8a8ff34aac7236e89bd75b91d Mon Sep 17 00:00:00 2001 From: Harshith Mullapudi Date: Thu, 28 Aug 2025 12:35:13 +0530 Subject: [PATCH] fix: oauth token refresh for basic --- apps/webapp/app/routes/oauth.token.tsx | 40 ++++++++++++++------ apps/webapp/app/services/email.server.ts | 4 +- apps/webapp/app/services/mcp.server.ts | 1 + apps/webapp/app/services/oauth2.server.ts | 8 +++- apps/webapp/app/utils/mcp/session-manager.ts | 1 - apps/webapp/server.ts | 4 +- hosting/docker/docker-compose.yaml | 5 +++ 7 files changed, 45 insertions(+), 18 deletions(-) diff --git a/apps/webapp/app/routes/oauth.token.tsx b/apps/webapp/app/routes/oauth.token.tsx index 2d0495f..562c6de 100644 --- a/apps/webapp/app/routes/oauth.token.tsx +++ b/apps/webapp/app/routes/oauth.token.tsx @@ -20,6 +20,27 @@ export const action = async ({ request }: ActionFunctionArgs) => { const contentType = request.headers.get("content-type"); let body: any; let tokenRequest: OAuth2TokenRequest; + const authHeader = request.headers.get("authorization"); + let basicAuthClientId: string | undefined; + let basicAuthClientSecret: string | undefined; + + if (authHeader?.startsWith("Basic ")) { + try { + const encoded = authHeader.slice(6); // Remove "Basic " prefix + const decoded = Buffer.from(encoded, "base64").toString("utf-8"); + const [clientId, clientSecret] = decoded.split(":"); + basicAuthClientId = clientId; + basicAuthClientSecret = clientSecret; + } catch (error) { + return json( + { + error: OAuth2Errors.INVALID_CLIENT, + error_description: "Invalid Basic authorization header", + }, + { status: 401 }, + ); + } + } // Support both JSON and form-encoded data if (contentType?.includes("application/json")) { @@ -28,8 +49,8 @@ export const action = async ({ request }: ActionFunctionArgs) => { grant_type: body.grant_type, code: body.code || undefined, redirect_uri: body.redirect_uri || undefined, - client_id: body.client_id, - client_secret: body.client_secret || undefined, + client_id: basicAuthClientId || body.client_id, + client_secret: basicAuthClientSecret || body.client_secret || undefined, code_verifier: body.code_verifier || undefined, }; } else { @@ -41,8 +62,11 @@ export const action = async ({ request }: ActionFunctionArgs) => { grant_type: formData.get("grant_type") as string, code: (formData.get("code") as string) || undefined, redirect_uri: (formData.get("redirect_uri") as string) || undefined, - client_id: formData.get("client_id") as string, - client_secret: (formData.get("client_secret") as string) || undefined, + client_id: basicAuthClientId || (formData.get("client_id") as string), + client_secret: + basicAuthClientSecret || + (formData.get("client_secret") as string) || + undefined, code_verifier: (formData.get("code_verifier") as string) || undefined, }; } @@ -70,14 +94,6 @@ export const action = async ({ request }: ActionFunctionArgs) => { ); } - if (!tokenRequest.client_id || !tokenRequest.client_secret) { - const clientData = await oauth2Service.getClientForCode( - tokenRequest.code, - ); - tokenRequest.client_id = clientData.client_id as string; - tokenRequest.client_secret = clientData.client_secret; - } - // Validate client try { await oauth2Service.validateClient( diff --git a/apps/webapp/app/services/email.server.ts b/apps/webapp/app/services/email.server.ts index 55e2190..c27a65b 100644 --- a/apps/webapp/app/services/email.server.ts +++ b/apps/webapp/app/services/email.server.ts @@ -57,13 +57,13 @@ function buildTransportOptions(): MailTransportOptions { export async function sendMagicLinkEmail(options: any): Promise { logger.debug("Sending magic link email", { - emailAddress: options.emailAddress, + email: options.email, }); try { return await client.send({ email: "magic_link", - to: options.emailAddress, + to: options.email, magicLink: options.magicLink, }); } catch (error) { diff --git a/apps/webapp/app/services/mcp.server.ts b/apps/webapp/app/services/mcp.server.ts index b5d6278..e7365fd 100644 --- a/apps/webapp/app/services/mcp.server.ts +++ b/apps/webapp/app/services/mcp.server.ts @@ -14,6 +14,7 @@ import { callMemoryTool, memoryTools } from "~/utils/mcp/memory"; import { logger } from "~/services/logger.service"; import { type Response, type Request } from "express"; import { getWorkspaceByUser } from "~/models/workspace.server"; +import { Workspace } from "@prisma/client"; const QueryParams = z.object({ source: z.string().optional(), diff --git a/apps/webapp/app/services/oauth2.server.ts b/apps/webapp/app/services/oauth2.server.ts index a374d21..92d6990 100644 --- a/apps/webapp/app/services/oauth2.server.ts +++ b/apps/webapp/app/services/oauth2.server.ts @@ -467,11 +467,15 @@ export class OAuth2Service { throw new Error(OAuth2Errors.INVALID_GRANT); } - // Validate PKCE if required - if (authCode.codeChallenge) { + // Validate PKCE if required //TODO: cursor is failing to send right pkce + if ( + authCode.codeChallenge && + params.redirectUri.includes("cursor:://anysphere") + ) { if (!params.codeVerifier) { throw new Error(OAuth2Errors.INVALID_REQUEST); } + if ( !this.validatePkceChallenge( params.codeVerifier, diff --git a/apps/webapp/app/utils/mcp/session-manager.ts b/apps/webapp/app/utils/mcp/session-manager.ts index 313c321..a7dfa1a 100644 --- a/apps/webapp/app/utils/mcp/session-manager.ts +++ b/apps/webapp/app/utils/mcp/session-manager.ts @@ -82,7 +82,6 @@ export class MCPSessionManager { id: session.id, source: session.source, integrations: session.integrations, - noIntegrations: session.noIntegrations, createdAt: session.createdAt, deleted: session.deleted || undefined, workspaceId: session.workspaceId || undefined, diff --git a/apps/webapp/server.ts b/apps/webapp/server.ts index e82f87b..254d2b9 100644 --- a/apps/webapp/server.ts +++ b/apps/webapp/server.ts @@ -21,7 +21,9 @@ async function init() { ? () => viteDevServer.ssrLoadModule("virtual:remix/server-build") : await import("./build/server/index.js"); - const module = build.entry?.module; + const module = viteDevServer + ? (await build()).entry.module + : build.entry?.module; remixHandler = createRequestHandler({ build }); diff --git a/hosting/docker/docker-compose.yaml b/hosting/docker/docker-compose.yaml index c7bef50..8830f73 100644 --- a/hosting/docker/docker-compose.yaml +++ b/hosting/docker/docker-compose.yaml @@ -37,6 +37,11 @@ services: - TRIGGER_SECRET_KEY=${TRIGGER_SECRET_KEY} - TRIGGER_API_URL=${API_ORIGIN} - POSTGRES_DB=${POSTGRES_DB} + - EMAIL_TRANSPORT=${EMAIL_TRANSPORT} + - REPLY_TO_EMAIL=${REPLY_TO_EMAIL} + - FROM_EMAIL=${FROM_EMAIL} + - RESEND_API_KEY=${RESEND_API_KEY} + - COHERE_API_KEY=${COHERE_API_KEY} ports: - "3033:3000" depends_on: