Skip to content

Commit 8de5853

Browse files
authored
ENG-1762 Rewrite all supabase access as server-side components (#1042)
1 parent 69593ed commit 8de5853

6 files changed

Lines changed: 154 additions & 127 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
Card,
3+
CardContent,
4+
CardHeader,
5+
CardTitle,
6+
} from "@repo/ui/components/ui/card";
7+
8+
const Page = async ({
9+
searchParams,
10+
}: {
11+
searchParams: Promise<{ error: string }>;
12+
}) => {
13+
const params = await searchParams;
14+
15+
return (
16+
<div className="flex min-h-svh w-full items-center justify-center p-6 md:p-10">
17+
<div className="w-full max-w-sm">
18+
<div className="flex flex-col gap-6">
19+
<Card>
20+
<CardHeader>
21+
<CardTitle className="text-2xl">
22+
Sorry, something went wrong.
23+
</CardTitle>
24+
</CardHeader>
25+
<CardContent>
26+
{params?.error ? (
27+
<p className="text-muted-foreground text-sm">
28+
Code error: {params.error}
29+
</p>
30+
) : (
31+
<p className="text-muted-foreground text-sm">
32+
An unspecified error occurred.
33+
</p>
34+
)}
35+
</CardContent>
36+
</Card>
37+
</div>
38+
</div>
39+
</div>
40+
);
41+
};
42+
43+
export default Page;

apps/website/app/(home)/auth/token/page.tsx

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { createClient } from "~/utils/supabase/server";
3+
import internalError from "~/utils/internalErrorSsr";
4+
5+
export const GET = async (request: NextRequest): Promise<NextResponse> => {
6+
const params = request.nextUrl.searchParams;
7+
const token = params.get("t");
8+
const url = params.get("url");
9+
try {
10+
if (typeof token !== "string") throw new Error("Please provide a token");
11+
if (typeof url !== "string") throw new Error("Please provide a single URL");
12+
if (
13+
url.indexOf("://") >= 0 &&
14+
!url.startsWith(request.nextUrl.origin + "/")
15+
)
16+
throw new Error("Absolute URLs should be within the application");
17+
18+
const client = await createClient();
19+
const result = await client.rpc("get_secret_token", {
20+
token,
21+
});
22+
if (result.error) {
23+
internalError({ error: result.error, type: "get-secret-token" });
24+
throw new Error("Could not connect to DiscourseGraphs");
25+
}
26+
if (result.data == null) {
27+
internalError({ error: "missing token", type: "get-secret-token" });
28+
throw new Error("Could not retrieve information, please try again.");
29+
}
30+
if (typeof result.data !== "string") {
31+
internalError({
32+
error: "payload-not-string",
33+
type: "get-secret-token",
34+
});
35+
throw new Error(
36+
"DiscourseGraphs configuration error, the team has been warned",
37+
);
38+
}
39+
const data = JSON.parse(result.data) as {
40+
/* eslint-disable @typescript-eslint/naming-convention */
41+
access_token: string;
42+
refresh_token: string;
43+
/* eslint-enable @typescript-eslint/naming-convention */
44+
};
45+
if (
46+
!data ||
47+
typeof data !== "object" ||
48+
!data.access_token ||
49+
!data.refresh_token
50+
) {
51+
internalError({ error: "misshaped-payload", type: "get-secret-token" });
52+
throw new Error(
53+
"DiscourseGraphs configuration error, the team has been warned",
54+
);
55+
}
56+
const response = await client.auth.setSession(data);
57+
if (response.error) {
58+
throw response.error;
59+
}
60+
} catch (error) {
61+
return NextResponse.redirect(
62+
new URL(
63+
"/auth/error?error=" +
64+
encodeURIComponent(
65+
error instanceof Error
66+
? error.message
67+
: "Unkown error while logging you in.",
68+
),
69+
request.nextUrl,
70+
),
71+
);
72+
}
73+
return NextResponse.redirect(
74+
new URL(url, url.startsWith("http") ? undefined : request.nextUrl),
75+
);
76+
};

apps/website/app/components/auth/LoginWithToken.tsx

Lines changed: 0 additions & 97 deletions
This file was deleted.

apps/website/app/utils/supabase/middleware.ts renamed to apps/website/app/utils/supabase/proxy.ts

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,24 @@ import { NextResponse, type NextRequest } from "next/server";
33
import { envContents } from "@repo/database/dbDotEnv";
44

55
// This would allow to create Next pages gated by a login middleware,
6-
// as described here: https://nextjs.org/docs/app/api-reference/file-conventions/middleware
7-
// Not usable yet, waiting for ENG-373
8-
// Inspired by https://supabase.com/ui/docs/nextjs/password-based-auth
6+
// as described here: https://supabase.com/docs/guides/auth/server-side/creating-a-client
97

108
export const updateSession = async (request: NextRequest) => {
9+
let supabaseResponse = NextResponse.next({
10+
request,
11+
});
1112
const dbEnv = envContents();
1213
const supabaseUrl = dbEnv.SUPABASE_URL;
1314
const supabaseKey = dbEnv.SUPABASE_PUBLISHABLE_KEY;
15+
if (supabaseUrl === undefined || supabaseKey === undefined)
16+
throw new Error("Configuration error: supabase variables not configured.");
1417

15-
if (!supabaseUrl || !supabaseKey) {
16-
throw new Error("Missing required Supabase environment variables");
17-
}
18-
19-
let supabaseResponse = NextResponse.next({ request });
20-
18+
// With Fluid compute, don't put this client in a global environment
19+
// variable. Always create a new one on each request.
2120
const supabase = createServerClient(supabaseUrl, supabaseKey, {
2221
cookies: {
2322
getAll: () => request.cookies.getAll(),
24-
setAll: (cookiesToSet) => {
23+
setAll: (cookiesToSet, headers) => {
2524
cookiesToSet.forEach(({ name, value }) =>
2625
request.cookies.set(name, value),
2726
);
@@ -31,33 +30,39 @@ export const updateSession = async (request: NextRequest) => {
3130
cookiesToSet.forEach(({ name, value, options }) =>
3231
supabaseResponse.cookies.set(name, value, options),
3332
);
33+
Object.entries(headers).forEach(([key, value]) =>
34+
supabaseResponse.headers.set(key, value),
35+
);
3436
},
3537
},
3638
});
3739

3840
// Do not run code between createServerClient and
39-
// supabase.auth.getUser(). A simple mistake could make it very hard to debug
41+
// supabase.auth.getClaims(). A simple mistake could make it very hard to debug
4042
// issues with users being randomly logged out.
4143

42-
// IMPORTANT: DO NOT REMOVE auth.getUser()
44+
// IMPORTANT: If you remove getClaims() and you use server-side rendering
45+
// with the Supabase client, your users may be randomly logged out.
46+
47+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
48+
const { data } = await supabase.auth.getClaims();
4349

44-
const {
45-
data: { user },
46-
} = await supabase.auth.getUser();
50+
/* Wait on this until we have login
51+
const user = data?.claims;
4752
4853
if (
4954
!user &&
50-
!request.nextUrl.pathname.startsWith("/login") &&
5155
!request.nextUrl.pathname.startsWith("/auth")
5256
) {
5357
// no user, potentially respond by redirecting the user to the login page
5458
const url = request.nextUrl.clone();
5559
url.pathname = "/auth/login";
5660
return NextResponse.redirect(url);
5761
}
62+
*/
5863

59-
// IMPORTANT: You *must* return the supabaseResponse object as it is.
60-
// If you're creating a new response object with NextResponse.next() make sure to:
64+
// IMPORTANT: You *must* return the supabaseResponse object as it is. If you're
65+
// creating a new response object with NextResponse.next() make sure to:
6166
// 1. Pass the request in it, like so:
6267
// const myNewResponse = NextResponse.next({ request })
6368
// 2. Copy over the cookies, like so:

apps/website/proxy.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { type NextRequest } from "next/server";
2+
import { updateSession } from "~/utils/supabase/proxy";
3+
4+
export const proxy = async (request: NextRequest) =>
5+
await updateSession(request);
6+
7+
export const config = {
8+
matcher: [
9+
/* Only apply to /auth paths */
10+
"/(auth/.*)",
11+
],
12+
};

0 commit comments

Comments
 (0)