Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions src/server/middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,14 +331,12 @@ const handleKeypairAuth = async (args: {
}) as jsonwebtoken.JwtPayload;

// If `bodyHash` is provided, it must match a hash of the POST request body.
if (
req.method === "POST" &&
payload?.bodyHash &&
payload.bodyHash !== hashRequestBody(req)
) {
error =
"The request body does not match the hash in the access token. See: https://portal.thirdweb.com/engine/features/keypair-authentication";
throw error;
if (req.method === "POST" && payload?.bodyHash) {
const computedBodyHash = hashRequestBody(req);
if (computedBodyHash !== payload.bodyHash) {
error = `The request body does not match the hash in the access token. See: https://portal.thirdweb.com/engine/v2/features/keypair-authentication. [hash in access token: ${payload.bodyHash}, hash computed from request: ${computedBodyHash}]`;
throw error;
}
}
Comment on lines +334 to 340
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Harden bodyHash validation: handle empty bodies, avoid echoing hashes, support more HTTP methods, and throw Error objects

  • JSON.stringify(undefined) can throw via createHash.update; guard for missing/empty body.
  • Returning both hashes in the client-visible error leaks unnecessary detail.
  • Restricting to POST misses PUT/PATCH/DELETE with bodies.
  • Prefer throwing Error objects over strings for consistency.

Apply this diff within this block:

-    // If `bodyHash` is provided, it must match a hash of the POST request body.
-    if (req.method === "POST" && payload?.bodyHash) {
-      const computedBodyHash = hashRequestBody(req);
-      if (computedBodyHash !== payload.bodyHash) {
-        error = `The request body does not match the hash in the access token. See: https://portal.thirdweb.com/engine/v2/features/keypair-authentication. [hash in access token: ${payload.bodyHash}, hash computed from request: ${computedBodyHash}]`;
-        throw error;
-      }
-    }
+    // If `bodyHash` is provided, it must match a hash of the request body.
+    if (payload?.bodyHash && ["POST", "PUT", "PATCH", "DELETE"].includes(req.method)) {
+      const hasBody =
+        typeof req.body === "string" ||
+        (req.body !== null &&
+          typeof req.body === "object" &&
+          Object.keys(req.body as Record<string, unknown>).length > 0);
+      if (!hasBody) {
+        error =
+          'Request body is missing or empty while the token includes a "bodyHash". See: https://portal.thirdweb.com/engine/v2/features/keypair-authentication';
+        throw new Error(error);
+      }
+      const computedBodyHash = hashRequestBody(req);
+      if (computedBodyHash !== payload.bodyHash) {
+        error =
+          "The request body does not match the hash in the token. See: https://portal.thirdweb.com/engine/v2/features/keypair-authentication";
+        throw new Error(error);
+      }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (req.method === "POST" && payload?.bodyHash) {
const computedBodyHash = hashRequestBody(req);
if (computedBodyHash !== payload.bodyHash) {
error = `The request body does not match the hash in the access token. See: https://portal.thirdweb.com/engine/v2/features/keypair-authentication. [hash in access token: ${payload.bodyHash}, hash computed from request: ${computedBodyHash}]`;
throw error;
}
}
// If `bodyHash` is provided, it must match a hash of the request body.
if (payload?.bodyHash && ["POST", "PUT", "PATCH", "DELETE"].includes(req.method)) {
const hasBody =
typeof req.body === "string" ||
(req.body !== null &&
typeof req.body === "object" &&
Object.keys(req.body as Record<string, unknown>).length > 0);
if (!hasBody) {
error =
'Request body is missing or empty while the token includes a "bodyHash". See: https://portal.thirdweb.com/engine/v2/features/keypair-authentication';
throw new Error(error);
}
const computedBodyHash = hashRequestBody(req);
if (computedBodyHash !== payload.bodyHash) {
error =
"The request body does not match the hash in the token. See: https://portal.thirdweb.com/engine/v2/features/keypair-authentication";
throw new Error(error);
}
}


const { isAllowed, ip } = await checkIpInAllowlist(req);
Expand Down
Loading