Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Abstracting Next.js away #23

Closed
Gbuomprisco opened this issue Mar 30, 2024 · 10 comments
Closed

[Proposal] Abstracting Next.js away #23

Gbuomprisco opened this issue Mar 30, 2024 · 10 comments
Labels
enhancement New feature or request

Comments

@Gbuomprisco
Copy link

Hi!

I use this package with Next.js - and would love to use it with other frameworks - so they can run well in edge runtimes.

I'd love to know if there would be any interest in abstracting this package away from Next.js and perhaps exporting a framework-less version - while using a different library (perhaps in an npm workspace) for exporting framework-specific implementations (Next.js, Remix, Sveltekit, etc.).

Happy to contribute if so!

@amorey
Copy link
Member

amorey commented Mar 30, 2024

Definitely! That's a great idea. Do the other frameworks use the same edge runtime as Next.js? If so then adding support for them shouldn't take too much work because the edge-specific computations are all encapsulated in util.ts.

Let me know what you're thinking and how I can help.

@amorey amorey added the enhancement New feature or request label Mar 30, 2024
@Gbuomprisco
Copy link
Author

Awesome, thank you!

You could pretty much run all these frameworks (SvelteKit, Remix, Astro) at the edge using Vercel or Cloudflare Workers - and this update would unlock using this package for all of these.

I believe we could replace all the NextRequest interfaces with simply Web Standard Request (should be the same given the usage in this package).

Then - it's a matter of exporting the various implementations - although it's likely that it's only Next.js that needs the current middleware functionality (as I don't think there is anything similar in others). As long as the utils are exported vanilla - I think people can build their own variation of the Next.js middleware function.

I am not sure how we could export the implementations, but I think exporting framework-specific packages could be an idea (maybe we can create NPM modules in this repository to export/publish them so you don't need to create different repositories).

So for Next.js we'd export edge-csrf/nextjs (and having Next.js as a peer-dependency) while edge-csrf would only export the required utils without requiring next.js as a dependency.

Unfortunately, this would require a major version bump!

@amorey
Copy link
Member

amorey commented Apr 13, 2024

Here's a draft PR that adds sveltekit support via a new handle function: #30

The way you use it is by adding a server hook like this:

// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';
import { createHandle } from 'edge-csrf/sveltekit';

// initalize csrf protection handle
export const handle: Handle = createHandle({
  cookie: {
    secure: process.env.NODE_ENV === 'production',
  },
});

Here are full working examples that implement form processing via server actions in Vercel's edge runtime and Cloudflare Pages:
https://github.com/amorey/edge-csrf/tree/sveltekit/examples/sveltekit-vercel
https://github.com/amorey/edge-csrf/tree/sveltekit/examples/sveltekit-cloudflare

Let me know what you think. I'm new to SveleteKit so any feedback would be very much appreciated.

@amorey
Copy link
Member

amorey commented Apr 14, 2024

Quick update - I switched from a default export to a named export (createHandle) and updated the example code above. I also added working examples for sveltekit on vercel and cloudflare and posted the links above.

And here's a proposal for the nextjs API:

// middleware.ts
import { createHandler } from 'edge-csrf/nextjs';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const csrfHandler = createHandler({
  cookie: {
    secure: process.env.NODE_ENV === 'production',
  },
});

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

  // csrf protection
  const csrfError = await csrfHandler(request, response);

  // check result
  if (csrfError) {
    return new NextResponse('invalid csrf token', { status: 403 });
  }

  return response;
}

@Gbuomprisco
Copy link
Author

Quick update - I switched from a default export to a named export (createHandle) and updated the example code above. I also added working examples for sveltekit on vercel and cloudflare and posted the links above.

And here's a proposal for the nextjs API:

// middleware.ts
import { createHandler } from 'edge-csrf/nextjs';
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const csrfHandler = createHandler({
  cookie: {
    secure: process.env.NODE_ENV === 'production',
  },
});

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

  // csrf protection
  const csrfError = await csrfHandler(request, response);

  // check result
  if (csrfError) {
    return new NextResponse('invalid csrf token', { status: 403 });
  }

  return response;
}

That looks great!

The only concern is that the dependencies will require (or download) Next.js and Sveltekit - while a multi-package (which definitely adds dev overhead) would avoid.

The ideal scenario (in my mind):

edge-csrf - core library - works with Web Standard Request (or simply accepts values). Can be used or adapted in any way by the consumer.
edge-csrf/nextjs - library that implements the Next.js middleware
edge-csrf/sveltekit - library that implements the Sveltekit hooks

This could be done using npm/pnpm workspaces from within this repository.

I've noticed you cut a v2 so for for thought about this!

@amorey
Copy link
Member

amorey commented Apr 18, 2024

@Gbuomprisco

Here's a release candidate for edge-csrf with support for Next.js and SvelteKit:
https://github.com/kubetail-org/edge-csrf/tree/2.0.0-rc7

To use it locally you can install [email protected]:

npm install [email protected]

Here are some things I'd like some feedback on:

  1. Is the documentation in the README clear and easy to follow?
  2. Are the createMiddleware() and createCsrfProtect() methods exposed by edge-csrf/nextjs sufficient for high-level/low-level integration with Next.js?
  3. Are the createHandle() and createCsrfProtect() methods exposed by edge-csrf/sveltekit sufficient for high-level/low-level integration with SvelteKit?
  4. Would it be better to expose the integrations as separate packages (e.g. @edge-csrf/nextjs, @edge-csrf/sveltekit)?

@amorey
Copy link
Member

amorey commented Apr 18, 2024

That looks great!

The only concern is that the dependencies will require (or download) Next.js and Sveltekit - while a multi-package (which definitely adds dev overhead) would avoid.

The ideal scenario (in my mind):

edge-csrf - core library - works with Web Standard Request (or simply accepts values). Can be used or adapted in any way by the consumer.
edge-csrf/nextjs - library that implements the Next.js middleware
edge-csrf/sveltekit - library that implements the Sveltekit hooks

This could be done using npm/pnpm workspaces from within this repository.

I've noticed you cut a v2 so for for thought about this!

Thanks for the feedback! Looks like I missed your message by 2 minutes. I've also been leaning towards releasing the code as separate packages:

@edge-csrf/core - Low-level API (e.g. createSecret(), createToken(), verifyToken())
@edge-csrf/nextjs - Next.js integration (e.g. createMiddleware(), createCsrfProtect())
@edge-csrf/sveltekit - SvelteKit integration (e.g. createHandle(), createCsrfProtect())

Doing so would make listing the dependencies easier and it would also solve some moduleResolution issues (conforming to moduleResolution: node is a pain). For now I don't think it makes sense to expose the underlying shared code between the framework integrations because I'm not confident that it's general enough for all use cases but the core methods should allow anyone to implement their own custom CSRF solution.

Let me know what you think!

@amorey
Copy link
Member

amorey commented Apr 19, 2024

@Gbuomprisco

Quick update - here's a version that splits the integrations into separate packages using a pnpm workspace:
https://github.com/kubetail-org/edge-csrf/tree/2.0.0-monorepo

Let me know what you think.

@amorey
Copy link
Member

amorey commented Apr 21, 2024

2.0.0 is live! Thanks so much for your help. Would you be interested in adding Remix and Astro integrations?

@amorey amorey closed this as completed Apr 21, 2024
@Gbuomprisco
Copy link
Author

2.0.0 is live! Thanks so much for your help. Would you be interested in adding Remix and Astro integrations?

Fantastic, thank you so much! Looks great and exactly how I thought it'd work.

I believe Remix does not yet have middleware (so users need to pass it from a root loader down to the page and protect actions manually), but the utilities from the core will make it still simple.

Maybe I can write a guide for the time being

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants