I've been trying to implement a reliable authentication flow for a Next.js project but I'm completely lost now. I've already seen the examples repo of Next.js. But I have a lot of questions for a complete solution.
I have a express.js API and a separate Next.js frontend project. All the data and the authentication is handled by the API. Frontend just renders the pages with SSR. If I would just create a monolith project, where rendering the pages and all the data is handled by a single server (with a custom server option for Next.js I mean), I would just use express-session and csurf. It would be a traditional way to manage sessions and create security against CSRF.
Express.js API is not a requirement. It is just an example. It could be a Django API, or a .Net Core API. The main point is, it is a separate server and a separate project.
How can I have a simple, yet reliable structure? I've examined some of my favorite websites (netlify, zeit.co, heroku, spectrum.chat etc). Some of them use localstorage to store access and refresh tokens (XSS vulnerable). Some of them use cookies and they are not even HTTPOnly (both XSS and CSRF vulnerable). And examples like spectrum.chat use the way I mentioned above (cookie-session + preventing csrf).
I know there is the giant hype around the JWT tokens. But I find them too complex. Most of the tutorials just skips all the expiration, token refreshing, token revocation, blacklisting, whitelisting etc.
And many of the session cookie examples for Next.js almost never mention CSRF. Honestly, authentication is always a big problem for me. One day I read that HTTPOnly cookies should be used, next day I see a giant popular site not even using them. Or they say "never store your tokens to localStorage", and boom some giant project just uses this method.
Can anyone show me some direction for this situation?