- /discord/connected: Discord's OAuth redirect target. Stashes code/state
in sessionStorage, strips them from the URL (replaceState), no-referrer
(metadata + response header), sends a signed-out user to
/login?next=/discord/connected and resumes, access_denied = "Nothing
changed", result card "Linked X: N ready, M need a fix".
- middleware.ts: the callback path joins NO_SESSION_COOKIE_GATE (plan
finding 2). Also needed for signed-in users: drb_session is
SameSite=Strict, so it is not sent on the cross-site redirect back from
discord.com.
- /login honours ?next= for an allowlist of one path (no open redirect).
- DiscordServersCard: Connect is the primary action with a radio-bot
picker (automatic / the bot for a system / the org's own bots); the
/drb link code moves to a collapsed secondary option and opens itself
when /discord/oauth/start answers 404.
- RadioBotsPanel: write-only client-secret field per bot (PUT/DELETE
/tokens/{id}/oauth), "Connect on/off", "N of 100 servers" with the
pool cap (90) warning.
- lib/discordOAuth.ts: the S6 client, kept out of c2api.ts; only ever
navigates to a discord.com /oauth2/authorize URL.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
15 lines
535 B
TypeScript
15 lines
535 B
TypeScript
import type { Metadata } from "next";
|
|
|
|
// The URL Discord sends the browser back to carries a single-use OAuth code.
|
|
// The page strips it from the address bar on load; no-referrer (also set as a
|
|
// response header in middleware.ts) covers anything that loads before that.
|
|
export const metadata: Metadata = {
|
|
title: "Connect a Discord server",
|
|
referrer: "no-referrer",
|
|
robots: { index: false, follow: false },
|
|
};
|
|
|
|
export default function DiscordConnectedLayout({ children }: { children: React.ReactNode }) {
|
|
return children;
|
|
}
|