|
| 1 | +// pages/api/auth/sso.ts |
| 2 | + |
1 | 3 | import type { NextApiRequest, NextApiResponse } from "next";
|
2 | 4 | import jwt from "jsonwebtoken";
|
3 | 5 |
|
4 | 6 | if (!process.env.METABASE_JWT_SHARED_SECRET) {
|
5 | 7 | throw new Error("Missing METABASE_JWT_SHARED_SECRET");
|
6 | 8 | }
|
7 |
| -if (!process.env.NEXT_PUBLIC_METABASE_INSTANCE_URL) { |
8 |
| - throw new Error("Missing NEXT_PUBLIC_METABASE_INSTANCE_URL"); |
| 9 | +if (!process.env.METABASE_INSTANCE_URL) { |
| 10 | + throw new Error("Missing METABASE_INSTANCE_URL"); |
9 | 11 | }
|
10 | 12 |
|
11 | 13 | const METABASE_JWT_SHARED_SECRET = process.env.METABASE_JWT_SHARED_SECRET;
|
12 | 14 | const METABASE_INSTANCE_URL = process.env.METABASE_INSTANCE_URL;
|
13 | 15 |
|
14 |
| -type MetabaseSession = { |
15 |
| - id: string; |
16 |
| -}; |
| 16 | +type JsonResponse = { jwt: string }; |
17 | 17 |
|
18 | 18 | export default async function handler(
|
19 | 19 | req: NextApiRequest,
|
20 |
| - res: NextApiResponse<MetabaseSession> |
| 20 | + res: NextApiResponse<JsonResponse | string> |
21 | 21 | ) {
|
22 |
| - // this should come from the session |
| 22 | + // In a real app you'd pull this from your session/cookie |
23 | 23 | const user = {
|
24 | 24 |
|
25 | 25 | firstName: "John",
|
26 | 26 | lastName: "Doe",
|
27 | 27 | group: "admin",
|
28 | 28 | };
|
29 | 29 |
|
| 30 | + // Sign a Metabase SSO JWT (10min expiration) |
30 | 31 | const token = jwt.sign(
|
31 | 32 | {
|
32 | 33 | email: user.email,
|
33 | 34 | first_name: user.firstName,
|
34 | 35 | last_name: user.lastName,
|
35 | 36 | groups: [user.group],
|
36 |
| - exp: Math.round(Date.now() / 1000) + 60 * 10, // 10 minutes expiration |
| 37 | + exp: Math.floor(Date.now() / 1000) + 60 * 10, |
37 | 38 | },
|
38 |
| - // This is the JWT signing secret in your Metabase JWT authentication setting |
39 | 39 | METABASE_JWT_SHARED_SECRET
|
40 | 40 | );
|
41 | 41 |
|
| 42 | + // If ?response=json, return { jwt } |
42 | 43 | if (req.query.response === "json") {
|
43 |
| - res.write({ jwt: token }); |
44 |
| - return res.end(); |
| 44 | + return res.status(200).json({ jwt: token }); |
45 | 45 | }
|
46 |
| - |
| 46 | + // Otherwise proxy the SSO request to Metabase |
47 | 47 | const ssoUrl = `${METABASE_INSTANCE_URL}/auth/sso?jwt=${token}`;
|
| 48 | + |
48 | 49 | try {
|
49 |
| - const response = await fetch(ssoUrl, { method: "GET" }); |
50 |
| - const session = await response.text(); |
51 |
| - |
52 |
| - res.write(session); |
53 |
| - return res.end(); |
54 |
| - } catch (error) { |
55 |
| - console.log("error", error); |
56 |
| - if (error instanceof Error) { |
57 |
| - res.write(error.message); |
58 |
| - return res.end(); |
59 |
| - } |
60 |
| - res.write("unknown error"); |
61 |
| - return res.end(); |
| 50 | + const mbRes = await fetch(ssoUrl); |
| 51 | + const html = await mbRes.text(); |
| 52 | + return res.status(mbRes.status).send(html); |
| 53 | + } catch (err) { |
| 54 | + console.error("Metabase SSO error:", err); |
| 55 | + const msg = err instanceof Error ? err.message : "Unknown error"; |
| 56 | + return res.status(500).send(msg); |
62 | 57 | }
|
63 | 58 | }
|
0 commit comments