kubetail-org / edge-csrf

CSRF protection library for JavaScript that runs on the edge runtime (with Next.js, SvelteKit, Express, Node-HTTP integrations)
MIT License
148 stars 9 forks source link

InvalidCharacterError: Invalid character #61

Closed BlairWoods closed 1 month ago

BlairWoods commented 1 month ago

Hi - I came across and interesting issue. I'm following a really similar example to the one here:

I'm seeing the error message:

InvalidCharacterError: Invalid character 'InvalidCharacterError: Invalid character …t\dist\server\lib\start-server.js:141:13)', message: 'Invalid character', Symbol(NextjsError): 'edge-server'}

This seems to be happening in the middleware file. Any ideas what could be causing this? My middleware code is relatively simple:

  // return csrf token.
  if (req.nextUrl.pathname === '/csrf-token') {
    return NextResponse.json({ csrfToken: req.headers.get('X-CSRF-Token') || 'missing' });
  }

  const response = NextResponse.next();
  try {
    const csrfToken = await csrfProtect(req, response);
    console.log('csrfToken', csrfToken);

  } catch (err) {
    if (err instanceof CsrfError) {
      return new NextResponse('invalid csrf token', { status: 403 });
    }

    throw err;
  }

I'm using Nextjs 14.

amorey commented 1 month ago

Happy to help but I need more info. Can you share code that reproduces the problem?

BlairWoods commented 1 month ago

Awesome - thanks for your help.

In my middleware file, I have this code (the same code taken from one of your examples):

import { CsrfError, createCsrfProtect } from '@edge-csrf/nextjs';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const csrfProtect = createCsrfProtect({
  cookie: {
    secure: true // process.env.NODE_ENV === 'production',
  },
});

export async function middleware(request: NextRequest) {
  const response = NextResponse.next();

  // csrf protection
  try {
    await csrfProtect(request, response);
  } catch (err) {
    if (err instanceof CsrfError) return new NextResponse('invalid csrf token', { status: 403 });
    throw err;
  }

  // return token (for use in static-optimized-example)
  if (request.nextUrl.pathname === '/csrf-token') {
    return NextResponse.json({ csrfToken: response.headers.get('X-CSRF-Token') || 'missing' });
  }

  return response;
}

This is the specific code that causes the error:

  try {
    await csrfProtect(request, response);
  } catch (err) {
    if (err instanceof CsrfError) return new NextResponse('invalid csrf token', { status: 403 });
    throw err;
  }

An error is thrown:

InvalidCharacterError: Invalid character 'InvalidCharacterError: Invalid character …t\dist\server\lib\start-server.js:141:13)', message: 'Invalid character', Symbol(NextjsError): 'edge-server'}

I'm running this locally. This middleware file I have normally has a lot more in it - but I've stripped it right back for testing this.

amorey commented 1 month ago

Thanks, is there a specific request that's triggering the error or are you seeing it on every request? Are you using app router, pages router? Can you can share more info especially about the request (GET, POST, payload, etc.)?

BlairWoods commented 1 month ago

I'm using the app router. To be more specific - I have a login page. This login page has a form. I haven't included the token on this form yet (I took it out for testing). Behind the scenes I'm using Next-Auth. The error is occurring on every request - page reloads etc. Whenever the middleware is hit.

amorey commented 1 month ago

Here's a barebones Next.js 14 app using app router with next-auth and edge-csrf installed: https://github.com/kubetail-org/nextjs-breakme

After you install it and go to http://localhost:3000 you should see this:

Screenshot 2024-09-18 at 10 04 28 AM

Currently next-auth isn't configured to pass the csrf token on POSTs so you'll get an invalid csrf token error when you click on Sign in > Github but that's expected.

Let me know how to modify the code to produce the error you're seeing. Feel free to submit a PR if that's easier.

BlairWoods commented 1 month ago

Awesome - thanks for your help. I'll try out the above and integrate it into my solution today.

BlairWoods commented 1 month ago

And now strangely, it works. I started from scratch, removed my code, used yours, and now it works. There isn't much difference between my original code and the example you provided - but I must have made a mistake along the way somewhere.

Thanks for your help with this - it's all working now :)

amorey commented 1 month ago

Hmm that's interesting... at least it's working now. If you run into the bug again, let me know.

amorey commented 2 weeks ago

I came across an unhandled InvalidCharacterError in the server action example and fixed it here: https://github.com/kubetail-org/edge-csrf/pull/72. Maybe that was the same error you came across as well.