Skip to content

Commit 627e437

Browse files
committed
feat: validate token locally using jwt secret
1 parent fb377f4 commit 627e437

File tree

6 files changed

+29
-21
lines changed

6 files changed

+29
-21
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ POSTGRES_DB=postgres
1616
###
1717
SUPABASE_URL=https://example.supabase.co
1818
SUPABASE_PK=example-key
19+
SUPABASE_AUTH_JWT_SECRET=abcdefghijklmnopqrstuvwxzyz1234567890

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"author": "",
2929
"license": "ISC",
3030
"devDependencies": {
31+
"@types/jsonwebtoken": "^9.0.6",
3132
"@typescript-eslint/eslint-plugin": "^7.11.0",
3233
"@typescript-eslint/parser": "^7.11.0",
3334
"@vitest/coverage-v8": "^2.0.0",
@@ -68,6 +69,7 @@
6869
"drizzle-zod": "^0.5.1",
6970
"express": "^4.19.2",
7071
"helmet": "^7.1.0",
72+
"jsonwebtoken": "^9.0.2",
7173
"pg": "^8.11.5",
7274
"pino": "^9.1.0",
7375
"pino-http": "^10.1.0"

src/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export const ENV = process.env.NODE_ENV ?? "development";
99

1010
export const getStage = (env: string): Stage => {
1111
if (!stages.includes(env as Stage)) {
12-
logger.error(`Invalid environment: ${ENV}`);
1312
throw new Error(`Invalid environment: ${ENV}`);
1413
}
1514
return env as Stage;
@@ -32,5 +31,6 @@ export const config = {
3231
db_password: process.env.POSTGRES_PASSWORD || "postgres",
3332
db_name: process.env.POSTGRES_DB || "test",
3433
supabaseUrl: process.env.SUPABASE_URL || "https://example.supabase.co",
35-
supabaseKey: process.env.SUPABASE_PK || "example-key"
34+
supabaseKey: process.env.SUPABASE_PK || "example-key",
35+
jwtSecret: process.env.SUPABASE_AUTH_JWT_SECRET || "super-secret-key-that-should-be-replaced"
3636
};

src/handlers/auth/auth.methods.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import jwt from "jsonwebtoken";
2+
import { config } from "../../config.ts";
3+
import { logger } from "@/helpers/index.ts";
4+
5+
export const verifyToken = async (token: string) => {
6+
try {
7+
return jwt.verify(token, config.jwtSecret) as { sub: string };
8+
} catch (err) {
9+
logger.error("Token validation failed:", err);
10+
return null;
11+
}
12+
};

src/handlers/profiles/profiles.handlers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export async function getProfiles(req: Request, res: Response) {
1818

1919
const result = await getProfilesByAccountId(id);
2020

21-
const response = gatewayResponse().success(200, result, "Fetched profiles for account");
21+
const response = gatewayResponse().success(200, result, `Fetched profiles for account: ${id}`);
2222

2323
return res.status(response.code).send(response);
2424
} catch (err) {

src/middleware/isAuthenticated.ts

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { logger, gatewayResponse, permissions } from "@/helpers/index.ts";
2-
import { supabase } from "@/services/supabase.ts";
32
import type { Route } from "@/helpers/index.ts";
43
import type { NextFunction, Request, Response } from "express";
54
import type { Method } from "@/helpers/permissions/permissions.ts";
5+
import { verifyToken } from "@/handlers/auth/auth.methods.ts";
66

77
const getIpFromRequest = (req: Request): string | undefined => {
88
const ips =
@@ -18,6 +18,7 @@ export const isAuthenticated = async (req: Request, res: Response, next: NextFun
1818
const token = authHeader && authHeader.split(" ")[1];
1919

2020
const routeKey = (req.baseUrl + req.route.path) as Route;
21+
2122
const routeMethod = req.method as Method;
2223

2324
const resourcePermissions = permissions.permissions.get(routeKey);
@@ -33,34 +34,26 @@ export const isAuthenticated = async (req: Request, res: Response, next: NextFun
3334
return next();
3435
}
3536

36-
if (!token && requiresAuth) {
37+
if (!token) {
3738
logger.error({ msg: "isAuthenticated: A token is required for authentication", routeKey, routeMethod });
3839

3940
return res.status(403).send("A token is required for authentication");
4041
}
4142

4243
try {
43-
// Verify token using your auth service.
44+
const verifiedToken = await verifyToken(token);
45+
console.log("verifiedToken", verifiedToken);
4446

45-
// TODO use a local db user and bypass token verification.
46-
const user = { id: "dd715937-ad7c-4a18-8214-0bd4d3c062a4" };
47-
// <-- Comment out the following block to use a local db user and bypass supabase
48-
// const {
49-
// data: { user },
50-
// error
51-
// } = await supabase.auth.getUser(token);
47+
if (!verifiedToken) {
48+
throw new Error("Invalid token");
49+
}
5250

53-
// if (error || !user) {
54-
// throw new Error(error?.message, {
55-
// cause: error
56-
// });
57-
// }
58-
// End comment -->
51+
const { sub } = verifiedToken;
5952

60-
logger.debug({ msg: `Verified user token for id: ${user.id}` });
53+
logger.debug({ msg: `Verified user token for id: ${sub}` });
6154

6255
// Attach user to res.locals and verify permissions in isAuthorized middleware
63-
res.locals = { id: user.id, sub: user.id };
56+
res.locals = { id: sub, sub };
6457

6558
return next();
6659
} catch (err) {

0 commit comments

Comments
 (0)