Reputation: 278
Would love some help on a Vercel deployment. I created a _middleware.ts file that checks a JWT that a user has in their cookie.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { JwtPayload, verify } from 'jsonwebtoken'
export async function middleware(req: NextRequest) {
let response = NextResponse.next()
const url = req.nextUrl.clone()
const token = req.cookies['allow-list']
if (!token || token === 'deleted') {
return response
}
try {
const decodedToken = verify(
token,
process.env.TOKEN_SECRET as string
) as JwtPayload
} catch (e) {}
return response
}
However, because of it, when I try to build my project, I get the following error: "Dynamic Code Evaluation (e. g. 'eval', 'new Function') not allowed in Middleware pages/_middleware". Is there a way around this? It works when I'm running it locally.
[22:59:29.409] Cloning github.com/dimitriborgers/test (Branch: master, Commit: efc1977)
[22:59:30.051] Cloning completed: 642.161ms
[22:59:30.427] Installing build runtime...
[22:59:34.350] Build runtime installed: 3.924s
[22:59:35.048] Looking up build cache...
[22:59:35.297] Build Cache not found
[22:59:35.503] Installing dependencies...
[22:59:35.507] Detected `package-lock.json` generated by npm 7...
[22:59:54.367]
[22:59:54.367] added 519 packages in 19s
[22:59:54.367]
[22:59:54.367] 97 packages are looking for funding
[22:59:54.367] run `npm fund` for details
[22:59:54.386] Detected Next.js version: 12.1.0
[22:59:54.392] Detected `package-lock.json` generated by npm 7...
[22:59:54.392] Running "npm run build"
[22:59:54.673]
[22:59:54.673] > build
[22:59:54.673] > next build
[22:59:54.673]
[22:59:55.312] Attention: Next.js now collects completely anonymous telemetry regarding usage.
[22:59:55.312] This information is used to shape Next.js' roadmap and prioritize features.
[22:59:55.312] You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
[22:59:55.312] https://nextjs.org/telemetry
[22:59:55.313]
[22:59:55.351] info - Checking validity of types...
[22:59:58.776] warn - No ESLint configuration detected. Run next lint to begin setup
[22:59:58.781] info - Creating an optimized production build...
[22:59:58.786] warn - using beta Middleware (not covered by semver) - https://nextjs.org/docs/messages/beta-middleware
[23:00:22.847] Failed to compile.
[23:00:22.847]
[23:00:22.847] ./node_modules/function-bind/implementation.js
[23:00:22.847] Dynamic Code Evaluation (e. g. 'eval', 'new Function') not allowed in Middleware pages/_middleware
[23:00:22.848]
[23:00:22.848] Import trace for requested module:
[23:00:22.848] ./node_modules/function-bind/index.js
[23:00:22.848] ./node_modules/call-bind/index.js
[23:00:22.848] ./node_modules/call-bind/callBound.js
[23:00:22.848] ./node_modules/which-typed-array/index.js
[23:00:22.848] ./node_modules/util/support/types.js
[23:00:22.848] ./node_modules/util/util.js
[23:00:22.848] ./node_modules/jws/lib/sign-stream.js
[23:00:22.849] ./node_modules/jws/index.js
[23:00:22.849] ./node_modules/jsonwebtoken/decode.js
[23:00:22.849] ./node_modules/jsonwebtoken/index.js
[23:00:22.849] ./pages/_middleware.ts
[23:00:22.849]
[23:00:22.849] ./node_modules/get-intrinsic/index.js
[23:00:22.849] Dynamic Code Evaluation (e. g. 'eval', 'new Function') not allowed in Middleware pages/_middleware
[23:00:22.849]
[23:00:22.849] Import trace for requested module:
[23:00:22.849] ./node_modules/call-bind/callBound.js
[23:00:22.849] ./node_modules/which-typed-array/index.js
[23:00:22.849] ./node_modules/util/support/types.js
[23:00:22.849] ./node_modules/util/util.js
[23:00:22.849] ./node_modules/jws/lib/sign-stream.js
[23:00:22.849] ./node_modules/jws/index.js
[23:00:22.850] ./node_modules/jsonwebtoken/decode.js
[23:00:22.850] ./node_modules/jsonwebtoken/index.js
[23:00:22.850] ./pages/_middleware.ts
[23:00:22.850]
[23:00:22.850] ./node_modules/has/src/index.js
[23:00:22.850] Dynamic Code Evaluation (e. g. 'eval', 'new Function') not allowed in Middleware pages/_middleware
[23:00:22.850]
[23:00:22.850] Import trace for requested module:
[23:00:22.850] ./node_modules/get-intrinsic/index.js
[23:00:22.850] ./node_modules/call-bind/callBound.js
[23:00:22.850] ./node_modules/which-typed-array/index.js
[23:00:22.850] ./node_modules/util/support/types.js
[23:00:22.850] ./node_modules/util/util.js
[23:00:22.850] ./node_modules/jws/lib/sign-stream.js
[23:00:22.850] ./node_modules/jws/index.js
[23:00:22.850] ./node_modules/jsonwebtoken/decode.js
[23:00:22.851] ./node_modules/jsonwebtoken/index.js
[23:00:22.851] ./pages/_middleware.ts
[23:00:22.851]
[23:00:22.851] ./node_modules/is-generator-function/index.js
[23:00:22.851] Dynamic Code Evaluation (e. g. 'eval', 'new Function') not allowed in Middleware pages/_middleware
[23:00:22.851]
[23:00:22.851] Import trace for requested module:
[23:00:22.851] ./node_modules/util/support/types.js
[23:00:22.852] ./node_modules/util/util.js
[23:00:22.852] ./node_modules/jws/lib/sign-stream.js
[23:00:22.852] ./node_modules/jws/index.js
[23:00:22.852] ./node_modules/jsonwebtoken/decode.js
[23:00:22.852] ./node_modules/jsonwebtoken/index.js
[23:00:22.852] ./pages/_middleware.ts
[23:00:22.853]
[23:00:22.853] ./node_modules/next/dist/compiled/vm-browserify/index.js
[23:00:22.854] Dynamic Code Evaluation (e. g. 'eval', 'new Function') not allowed in Middleware pages/_middleware
[23:00:22.854]
[23:00:22.854] Import trace for requested module:
[23:00:22.854] ./node_modules/jwa/index.js
[23:00:22.854] ./node_modules/jws/lib/sign-stream.js
[23:00:22.854] ./node_modules/jws/index.js
[23:00:22.854] ./node_modules/jsonwebtoken/decode.js
[23:00:22.855] ./node_modules/jsonwebtoken/index.js
[23:00:22.855] ./pages/_middleware.ts
[23:00:22.855]
[23:00:22.855]
[23:00:22.855] > Build failed because of webpack errors
[23:00:22.886] Error: Command "npm run build" exited with 1
Upvotes: 7
Views: 6032
Reputation: 2494
just wanted to add a solution if you don't want to get rid of jsonwebtoken
.
You can add this config to your middleware file.
export const config = {
runtime: "edge",
unstable_allowDynamic: [
'**/node_modules/lodash/**/*.js',
],
};
And add whatever other package is calling eval. The current jsonwebtoken
version using decode
should fix it.
As you are using verify
, you might need to add other libraries to this unstable_allowDynamic
.
Also, the recommended solution, as others mentioned, is probably switching libraries.
Upvotes: 1
Reputation: 418
most native nodejs APIs are not supported
here is offially next js example jwt middleware source this code exapmle use jose jose repo
import { type NextRequest, NextResponse } from 'next/server'
import { verifyAuth } from '@lib/auth'
export const config = {
matcher: [ '/api/protected', '/protected' ],
}
export async function middleware(req: NextRequest) {
// validate the user is authenticated
const verifiedToken = await verifyAuth(req).catch((err) => {
console.error(err.message)
})
if (!verifiedToken) {
// if this an API request, respond with JSON
if (req.nextUrl.pathname.startsWith('/api/')) {
return new NextResponse(
JSON.stringify({ 'error': { message: 'authentication required' } }),
{ status: 401 });
}
// otherwise, redirect to the set token page
else {
return NextResponse.redirect(new URL('/', req.url))
}
}
}
Upvotes: 1
Reputation: 1077
Since the middleware runtime is based on the browser and not the server, eval is not allowed in that position. Also, the middleware runtime maximum allowed duration is 1.5 seconds. Hence, we can't rely on obtaining the verification from another server from an Edge Function.
I had removed the use of jsonwebtoken
library completely and used jose
to overcome the issue and keep the codebase simplified. The code works on both browser and server runtimes enabling us to verify the user on the middleware layer itself.
Signing JWT
import * as jose from 'jose';
const jwtToken = await new jose.SignJWT({ userId: `your-data` })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('30d')
.sign(new TextEncoder().encode(`secret-key-phrase`));
Verifying JWT
This works on the middleware without any issues (Edge Function on Vercel).
import * as jose from 'jose';
try {
const { payload: jwtData } = await jose.jwtVerify(
jwtToken, new TextEncoder().encode(`secret-key-phrase`)
);
// jwtData.uid => `your-data`
} catch (error) {
console.log(error);
// JWT validation failed or token is invalid
}
Upvotes: 15
Reputation: 278
Using the @tsndr/cloudflare-worker-jwt library instead of jsonwebtoken works.
Upvotes: 0