szymmis / vite-express

⚡ @vitejs integration module for @expressjs
MIT License
585 stars 35 forks source link

Authentication Middleware #126

Closed IronCrystal closed 2 months ago

IronCrystal commented 5 months ago

My understanding is that ViteExpress will auto. attach a middlware to the express app that serves up the Vite assets (handles * endpoints).

How would I go about putting a middleware, for say authentication around these routes?

Is the only solution to use app.use(middleware) at the very end of my app and assume that all routes afterwards must follow the same authentication?

In my situation, I have a login page at /login which would have no authentication required, but I need to have authentication for all other pages of the app.

I'm not sure how to go about doing this with ViteExpress.

IronCrystal commented 5 months ago

Here's a bit more context of what I'm struggling with.

I have 5 routes currently. 4 of them must be authenticated, 1 is the login page (no authentication).

I am currently using this setup to get close to what I need, but it's still not great.

app.use(ViteExpress.static()); // Serve vite assets

app.get('/login', unauthenticatedUser); //If the user is authenticated, redirect to home page

 //These routes must be authenticated, but let vite express handle the response
app.get('/', authenticatedUser);
app.get('/trackers', authenticatedUser);
app.get('/analytics', authenticatedUser);
app.get('/settings', authenticatedUser);

function unauthenticatedUser(req: Request, res: Response, next: NextFunction) {
  if (!isAuthenticated) return next();
  else res.redirect('/');
}

function authenticatedUser(req: Request, res: Response, next: NextFunction) {
  if (isAuthenticated) return next();
  else res.redirect('/login');
};

In this scenario, the ViteExpress.static() is only serving the asset files, but not the index.html.

The login endpoint has a middleware that will redirect to / if the user is already logged in, but it will not handle the request if not signed in. It is "defaulting" to the Vite html middleware to serve the index.html file.

The other four routes have a middleware that will redirect to /login if the user isn't logged in, but they also do not handle the request. It uses vite-express to serve the index.html.

This is somewhat working for me, but I have the following concerns:

szymmis commented 5 months ago

Hi @IronCrystal, from your description I believe that you are very close to achieving what you want. For me this snipped does the trick:

import express from "express";
import ViteExpress from "vite-express";

const app = express();

app.use(ViteExpress.static());

function isPublicRoute(url: string) {
  return url.match("/login");
}

app.use((req, res, next) => {
  const isLoggedIn = req.headers.cookie?.includes("token");

  if (isLoggedIn) {
    if (req.url.match("/login")) {
      return res.redirect("/");
    } else {
      return next();
    }
  }

  return isPublicRoute(req.url) ? next() : res.redirect("/login");
});

app.post("/login", (req, res) => {
  res.cookie("token", "123456");
  res.redirect("/");
});

ViteExpress.listen(app, 3000, () =>
  console.log("Server is listening on port 3000...")
);

I don't need to specify handler for all the routes, I can just manipulate the isPublicRoute function to specify which URLs should be considered public and otherwise if you are not logged in you are getting redirected. I don't know if you want to display separate HTML files for login page etc. but if you do there is not much more needed to be done to make it work.

If I had a middleware that could force the return of index.html, then I could do this for the /login route. Right now it's relying on the "catchall" route to return it.

Could you elaborate a little bit more about why relying on this pass-through logic is bad in your case? For me it's simple: if you are not allowed to complete the request because you are not authenticated just redirect, otherwise let it through. But maybe this doesn't work in your case and I would like to hear more about it, so I can help you further.

szymmis commented 2 months ago

I'm closing this issue from inactivity. As always, feel free to continue it if you have any more questions about this matter.