fix: trying mcp auth with resource (#840)

This commit is contained in:
MaheshtheDev 2026-04-09 08:21:06 +00:00
parent 543c45a626
commit 8f1e8afaf9
3 changed files with 61 additions and 5 deletions

View file

@ -105,12 +105,16 @@ app.all("/mcp/*", async (c) => {
const token = authHeader?.replace(/^Bearer\s+/i, "")
const containerTag = c.req.header("x-sm-project")
const apiUrl = c.env.API_URL || DEFAULT_API_URL
const mcpURL =
c.env.API_URL === "http://localhost:8787"
? "http://localhost:8788"
: "https://mcp.supermemory.ai"
if (!token) {
return new Response("Unauthorized", {
status: 401,
headers: {
"WWW-Authenticate": `Bearer resource_metadata="/.well-known/oauth-protected-resource"`,
"WWW-Authenticate": `Bearer resource_metadata="${mcpURL}/.well-known/oauth-protected-resource"`,
"Access-Control-Expose-Headers": "WWW-Authenticate",
},
})
@ -149,7 +153,7 @@ app.all("/mcp/*", async (c) => {
status: 401,
headers: {
"Content-Type": "application/json",
"WWW-Authenticate": `Bearer error="invalid_token", resource_metadata="/.well-known/oauth-protected-resource"`,
"WWW-Authenticate": `Bearer error="invalid_token", resource_metadata="${mcpURL}/.well-known/oauth-protected-resource"`,
"Access-Control-Expose-Headers": "WWW-Authenticate",
},
},

View file

@ -1,6 +1,6 @@
"use client"
import { signIn } from "@lib/auth"
import { signIn, useSession } from "@lib/auth"
import { usePostHog } from "@lib/posthog"
import { TextSeparator } from "@ui/components/text-separator"
import { ExternalAuthButton } from "@ui/button/external-auth"
@ -18,6 +18,21 @@ import { dmSansClassName } from "@/lib/fonts"
import { cn } from "@lib/utils"
import { Logo } from "@ui/assets/Logo"
function isMcpOAuthAuthorizeContext(sp: Pick<URLSearchParams, "get">): boolean {
return sp.get("response_type") === "code" && Boolean(sp.get("client_id"))
}
function buildMcpAuthorizeResumeUrl(
sp: Pick<URLSearchParams, "toString">,
): string {
const backend =
process.env.NEXT_PUBLIC_BACKEND_URL ?? "https://api.supermemory.ai"
const p = new URLSearchParams(sp.toString())
p.delete("redirect")
p.delete("error")
return `${backend}/api/auth/mcp/authorize?${p.toString()}`
}
function AnimatedGradientBackground() {
return (
<div className="fixed inset-0 z-0 overflow-hidden">
@ -90,6 +105,17 @@ export default function LoginPage() {
const posthog = usePostHog()
const params = useSearchParams()
const { data: sessionData, isPending: sessionPending } = useSession()
const oauthQueryForResume = params.toString()
useEffect(() => {
if (sessionPending) return
if (!sessionData?.session) return
const sp = new URLSearchParams(oauthQueryForResume)
if (!isMcpOAuthAuthorizeContext(sp)) return
window.location.assign(buildMcpAuthorizeResumeUrl(sp))
}, [sessionPending, sessionData?.session, oauthQueryForResume])
// Get redirect URL from query params
const redirectUrl = params.get("redirect")
@ -97,6 +123,11 @@ export default function LoginPage() {
// Create callback URL that includes redirect parameter if provided
const getCallbackURL = () => {
const origin = window.location.origin
if (isMcpOAuthAuthorizeContext(params)) {
return buildMcpAuthorizeResumeUrl(params)
}
let finalUrl: URL
if (redirectUrl) {

View file

@ -1,5 +1,26 @@
import { redirect } from "next/navigation"
export default function Page() {
redirect("/login/new")
function serializeSearchParams(
sp: Record<string, string | string[] | undefined>,
): string {
const q = new URLSearchParams()
for (const [key, value] of Object.entries(sp)) {
if (value === undefined) continue
if (Array.isArray(value)) {
for (const v of value) q.append(key, v)
} else {
q.set(key, value)
}
}
return q.toString()
}
export default async function Page({
searchParams,
}: {
searchParams: Promise<Record<string, string | string[] | undefined>>
}) {
const sp = await searchParams
const query = serializeSearchParams(sp)
redirect(query ? `/login/new?${query}` : "/login/new")
}