feat(web): branded plugin header on /oauth/consent

Show the requesting plugin's icon + 'Connect <Name>' on the OAuth consent
page so users see exactly which first-party plugin (Claude Code, OpenCode,
OpenClaw, OpenAI Codex) is asking for access. Falls back to a generic
'An application wants to connect' for unknown/DCR-registered clients.

KNOWN_OAUTH_CLIENTS mirrors mono/packages/lib/plugins.ts; the two repos
don't share a package, so kept in sync manually (follow-up: shared lib).

Also add a 'codex' entry to PLUGIN_INFO in app/auth/connect/page.tsx for
the legacy sm_ key flow path (Codex CLI plugin).
This commit is contained in:
Mahesh Sanikommu 2026-05-13 15:20:30 -07:00
parent ffac43db93
commit 678c7c603b
2 changed files with 57 additions and 7 deletions

View file

@ -90,6 +90,17 @@ const PLUGIN_INFO: Record<string, PluginInfo> = {
],
icon: "/images/plugins/cursor.svg",
},
codex: {
name: "OpenAI Codex",
description:
"Persistent memory for OpenAI Codex CLI. Remembers your coding context, patterns, and decisions across sessions.",
features: [
"Auto-recalls relevant context before each prompt",
"Captures coding decisions and patterns automatically",
"Builds persistent user profile across projects",
],
icon: "/images/plugins/codex.svg",
},
}
function getPluginName(client: string): string {

View file

@ -6,6 +6,7 @@ import { cn } from "@lib/utils"
import { LogoFull } from "@ui/assets/Logo"
import { Popover, PopoverContent, PopoverTrigger } from "@ui/components/popover"
import { Building2, Check, ChevronDown, LoaderIcon } from "lucide-react"
import Image from "next/image"
import { useSearchParams } from "next/navigation"
import { Suspense, useState } from "react"
@ -19,6 +20,26 @@ const DATA_CAPABILITIES = [
"See your spaces (container tags) and create new ones",
] as const
// Mirrors mono/packages/lib/plugins.ts; kept in sync manually.
const KNOWN_OAUTH_CLIENTS: Record<string, { name: string; icon: string }> = {
"supermemory-claude-code": {
name: "Claude Code",
icon: "/images/plugins/claude-code.svg",
},
"supermemory-opencode": {
name: "OpenCode",
icon: "/images/plugins/opencode.svg",
},
"supermemory-openclaw": {
name: "OpenClaw",
icon: "/images/plugins/openclaw.svg",
},
"supermemory-codex": {
name: "OpenAI Codex",
icon: "/images/plugins/codex.svg",
},
}
function shortClientId(id: string): string {
return id.length > 12 ? `${id.slice(0, 4)}${id.slice(-4)}` : id
}
@ -53,6 +74,9 @@ function OAuthConsentContent() {
organizations?.find((o) => o.id === activeOrgId)?.name ?? null
const canSwitchOrg = (organizations?.length ?? 0) > 1
const clientId = params.get("client_id") ?? ""
const knownClient = clientId ? KNOWN_OAUTH_CLIENTS[clientId] : undefined
const requesterName = knownClient?.name ?? "An application"
const requesterIcon = knownClient?.icon ?? null
const scopes = (params.get("scope") ?? "").split(/\s+/).filter(Boolean)
const accountAccess = accountAccessLabels(scopes)
// A valid consent page is reached only via /oauth2/authorize, which appends a
@ -241,13 +265,28 @@ function OAuthConsentContent() {
<div className="h-px bg-[#1E293B]" />
</div>
<div className="text-center">
<h2 className="font-semibold text-[18px] text-[#FAFAFA]">
Authorize access
</h2>
<p className="mt-1 text-[13px] text-[#737373]">
An application wants to connect to your Supermemory account.
</p>
<div className="flex flex-col items-center gap-3 text-center">
{requesterIcon ? (
<div className="flex size-12 items-center justify-center rounded-[12px] border border-white/5 bg-[#080B0F]">
<Image
alt={requesterName}
className="size-7"
height={28}
src={requesterIcon}
width={28}
/>
</div>
) : null}
<div>
<h2 className="font-semibold text-[18px] text-[#FAFAFA]">
Connect {requesterName}
</h2>
<p className="mt-1 text-[13px] text-[#737373]">
{knownClient
? `${requesterName} wants to connect to your Supermemory account.`
: "An application wants to connect to your Supermemory account."}
</p>
</div>
</div>
<div className="rounded-[12px] bg-[#0D121A] p-4">