From 13a1382f8c100c828aaff566051870779026c2de Mon Sep 17 00:00:00 2001 From: Andrew Jiang Date: Thu, 3 Oct 2024 11:31:15 -0400 Subject: [PATCH] fix: redirect_uri should be set in edge config (#1591) --- packages/ui/app/src/auth/OAuth2Client.ts | 19 +++++++++---------- .../app/src/auth/getApiKeyInjectionConfig.ts | 4 ++-- packages/ui/app/src/auth/getAuthEdgeConfig.ts | 14 ++++++++++++-- packages/ui/app/src/auth/types.ts | 2 ++ .../PlaygroundAuthorizationForm.tsx | 2 +- .../api/fern-docs/auth/api-key-injection.ts | 9 +++------ .../src/pages/api/fern-docs/auth/callback.ts | 4 ++-- .../src/pages/api/fern-docs/auth/logout.ts | 5 ++++- .../pages/api/fern-docs/oauth/ory/callback.ts | 8 ++++---- .../api/fern-docs/oauth/webflow/callback.ts | 6 ++++-- 10 files changed, 43 insertions(+), 30 deletions(-) diff --git a/packages/ui/app/src/auth/OAuth2Client.ts b/packages/ui/app/src/auth/OAuth2Client.ts index 2d00078391..ffa99f5402 100644 --- a/packages/ui/app/src/auth/OAuth2Client.ts +++ b/packages/ui/app/src/auth/OAuth2Client.ts @@ -16,16 +16,15 @@ export class OAuth2Client { private readonly environment: string; private readonly scope: string | undefined; private readonly jwks: string | undefined; + private readonly redirectUri?: string; - constructor( - config: AuthEdgeConfigOAuth2Ory, - private readonly redirect_uri?: string, - ) { + constructor(config: AuthEdgeConfigOAuth2Ory) { this.clientId = config.clientId; this.clientSecret = config.clientSecret; this.environment = config.environment; this.scope = config.scope; this.jwks = config.jwks; + this.redirectUri = config.redirectUri; } public async getToken(code: string): Promise { @@ -34,8 +33,8 @@ export class OAuth2Client { form.append("client_secret", this.clientSecret); form.append("grant_type", "authorization_code"); form.append("client_id", this.clientId); - if (this.redirect_uri != null) { - form.append("redirect_uri", this.redirect_uri); + if (this.redirectUri != null) { + form.append("redirect_uri", this.redirectUri); } const response = await fetch(urlJoin(this.environment, "/token"), { @@ -55,8 +54,8 @@ export class OAuth2Client { form.append("client_secret", this.clientSecret); form.append("grant_type", "refresh_token"); form.append("client_id", this.clientId); - if (this.redirect_uri != null) { - form.append("redirect_uri", this.redirect_uri); + if (this.redirectUri != null) { + form.append("redirect_uri", this.redirectUri); } const response = await fetch(urlJoin(this.environment, "/token"), { @@ -74,8 +73,8 @@ export class OAuth2Client { const url = new URL(urlJoin(this.environment, "/auth")); url.searchParams.set("response_type", "code"); url.searchParams.set("client_id", this.clientId); - if (this.redirect_uri != null) { - url.searchParams.set("redirect_uri", this.redirect_uri); + if (this.redirectUri != null) { + url.searchParams.set("redirect_uri", this.redirectUri); } if (state != null) { url.searchParams.set("state", state); diff --git a/packages/ui/app/src/auth/getApiKeyInjectionConfig.ts b/packages/ui/app/src/auth/getApiKeyInjectionConfig.ts index 23331b9c6e..7291f31628 100644 --- a/packages/ui/app/src/auth/getApiKeyInjectionConfig.ts +++ b/packages/ui/app/src/auth/getApiKeyInjectionConfig.ts @@ -34,7 +34,7 @@ export async function getAPIKeyInjectionConfig( ): Promise { const config = await getAuthEdgeConfig(domain); if (config?.type === "oauth2" && config.partner === "ory" && config["api-key-injection-enabled"]) { - const client = new OAuth2Client(config, `https://${domain}/api/auth/callback`); + const client = new OAuth2Client(config); const tokens = cookies != null ? await client.getOrRefreshAccessTokenEdge(cookies) : undefined; if (tokens != null) { @@ -71,7 +71,7 @@ export async function getAPIKeyInjectionConfigNode( ): Promise { const config = await getAuthEdgeConfig(domain); if (config?.type === "oauth2" && config.partner === "ory" && config["api-key-injection-enabled"]) { - const client = new OAuth2Client(config, `https://${domain}/api/auth/callback`); + const client = new OAuth2Client(config); const tokens = cookies != null ? await client.getOrRefreshAccessTokenNode(cookies) : undefined; if (tokens != null) { diff --git a/packages/ui/app/src/auth/getAuthEdgeConfig.ts b/packages/ui/app/src/auth/getAuthEdgeConfig.ts index 6f5df55d67..a75f2e1521 100644 --- a/packages/ui/app/src/auth/getAuthEdgeConfig.ts +++ b/packages/ui/app/src/auth/getAuthEdgeConfig.ts @@ -1,3 +1,4 @@ +import { captureMessage } from "@sentry/nextjs"; import { get } from "@vercel/edge-config"; import { AuthEdgeConfig, AuthEdgeConfigSchema } from "./types"; @@ -8,8 +9,17 @@ export async function getAuthEdgeConfig(currentDomain: string): Promise { if (req.method !== "GET") { return new NextResponse(null, { status: 405 }); } + const domain = getXFernHostEdge(req); // The authorization code returned by AuthKit const code = req.nextUrl.searchParams.get("code"); const state = req.nextUrl.searchParams.get("state"); const error = req.nextUrl.searchParams.get("error"); const error_description = req.nextUrl.searchParams.get("error_description"); - const redirectLocation = state ?? req.nextUrl.origin; + const redirectLocation = state ?? `https://${domain}/`; if (error != null) { return redirectWithLoginError(redirectLocation, error_description ?? error); @@ -31,7 +32,6 @@ export default async function GET(req: NextRequest): Promise { return redirectWithLoginError(redirectLocation, "Couldn't login, please try again"); } - const domain = getXFernHostEdge(req); const config = await getAuthEdgeConfig(domain); if (config != null && config.type === "oauth2" && config.partner === "ory") { diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/auth/logout.ts b/packages/ui/docs-bundle/src/pages/api/fern-docs/auth/logout.ts index c06e2dae8d..76e181e775 100644 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/auth/logout.ts +++ b/packages/ui/docs-bundle/src/pages/api/fern-docs/auth/logout.ts @@ -1,10 +1,13 @@ +import { getXFernHostEdge } from "@/server/xfernhost/edge"; import { NextRequest, NextResponse } from "next/server"; export const runtime = "edge"; export default async function GET(req: NextRequest): Promise { + const domain = getXFernHostEdge(req); + const state = req.nextUrl.searchParams.get("state"); - const redirectLocation = state ?? req.nextUrl.origin; + const redirectLocation = state ?? `https://${domain}/`; const res = NextResponse.redirect(redirectLocation); res.cookies.delete("fern_token"); diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/oauth/ory/callback.ts b/packages/ui/docs-bundle/src/pages/api/fern-docs/oauth/ory/callback.ts index 9f9724fd71..50753196d1 100644 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/oauth/ory/callback.ts +++ b/packages/ui/docs-bundle/src/pages/api/fern-docs/oauth/ory/callback.ts @@ -8,7 +8,6 @@ import { withSecureCookie, } from "@fern-ui/ui/auth"; import { NextRequest, NextResponse } from "next/server"; -import urlJoin from "url-join"; export const runtime = "edge"; @@ -23,11 +22,13 @@ export default async function GET(req: NextRequest): Promise { return new NextResponse(null, { status: 405 }); } + const domain = getXFernHostEdge(req); + const code = req.nextUrl.searchParams.get("code"); const state = req.nextUrl.searchParams.get("state"); const error = req.nextUrl.searchParams.get("error"); const error_description = req.nextUrl.searchParams.get("error_description"); - const redirectLocation = state ?? req.nextUrl.origin; + const redirectLocation = state ?? `https://${domain}/`; if (error != null) { return redirectWithLoginError(redirectLocation, error_description ?? error); @@ -37,14 +38,13 @@ export default async function GET(req: NextRequest): Promise { return redirectWithLoginError(redirectLocation, "Couldn't login, please try again"); } - const domain = getXFernHostEdge(req); const config = await getAuthEdgeConfig(domain); if (config == null || config.type !== "oauth2" || config.partner !== "ory") { return redirectWithLoginError(redirectLocation, "Couldn't login, please try again"); } - const oauthClient = new OAuth2Client(config, urlJoin(`https://${domain}`, req.nextUrl.pathname)); + const oauthClient = new OAuth2Client(config); try { const { access_token, refresh_token } = await oauthClient.getToken(code); const token = OryAccessTokenSchema.parse(await oauthClient.decode(access_token)); diff --git a/packages/ui/docs-bundle/src/pages/api/fern-docs/oauth/webflow/callback.ts b/packages/ui/docs-bundle/src/pages/api/fern-docs/oauth/webflow/callback.ts index 9a34aefd80..bd99c5736d 100644 --- a/packages/ui/docs-bundle/src/pages/api/fern-docs/oauth/webflow/callback.ts +++ b/packages/ui/docs-bundle/src/pages/api/fern-docs/oauth/webflow/callback.ts @@ -16,11 +16,13 @@ export default async function GET(req: NextRequest): Promise { return new NextResponse(null, { status: 405 }); } + const domain = getXFernHostEdge(req); + const code = req.nextUrl.searchParams.get("code"); const state = req.nextUrl.searchParams.get("state"); const error = req.nextUrl.searchParams.get("error"); const error_description = req.nextUrl.searchParams.get("error_description"); - const redirectLocation = state ?? req.nextUrl.origin; + const redirectLocation = state ?? `https://${domain}/`; if (error != null) { return redirectWithLoginError(redirectLocation, error_description ?? error); @@ -30,7 +32,6 @@ export default async function GET(req: NextRequest): Promise { return redirectWithLoginError(redirectLocation, "Couldn't login, please try again"); } - const domain = getXFernHostEdge(req); const config = await getAuthEdgeConfig(domain); if (config == null || config.type !== "oauth2" || config.partner === "ory") { @@ -41,6 +42,7 @@ export default async function GET(req: NextRequest): Promise { const accessToken = await WebflowClient.getAccessToken({ clientId: config.clientId, clientSecret: config.clientSecret, + redirectUri: config.redirectUri, code, });