DEV Community

Cover image for Easy user authentication with Next.js

Easy user authentication with Next.js

Chris Garrett on June 03, 2020

Over the past couple of releases, Next.js has made some impressive additions which have transformed the way I develop with it. One of my favourite ...
Collapse
 
tsm012 profile image
Tsm012

Love the simplicity. However, after I am successfully authenticated, my user session is not available inside my getServerSideProps function, so a 404 is always returned even after a successful authentication and redirect. Any thoughts on why:

const user = req.session.get("user");

would work in the sessions.js file but be unavailable in the getServerSideProps function?

Collapse
 
mnengwa profile image
mnengwa • Edited

HI, @tsm012. How did you solve the above issue? I am experiencing the same issue.

Create a util in utils/cookies.js

import {withIronSession} from 'next-iron-session';

const cookie = {
    cookieName: process.env.COOKIE_NAME,
    password: process.env.COOKIE_SECRET,
    cookieOptions: {secure: process.env.NODE_ENV === 'production'},
};

export const guard = (handler) => {
    return withIronSession(handler, cookie);
};

export default cookie;
Enter fullscreen mode Exit fullscreen mode

Implement lookup logic

....
req.session.set('user', { user });

// persist session value
await req.session.save();

console.log(req.session.get('user'));
return res.status(201).json({success, message});
Enter fullscreen mode Exit fullscreen mode

Attempt to access the session value

export const getServerSideProps = guard(async (ctx) => {
    const {req} = ctx;

    const session = req.session.get();

    console.log({session});

    return {redirect: {destination: '/sign-in', permanent: false}};
});
Enter fullscreen mode Exit fullscreen mode

At this point, the session is empty e.g { }

Collapse
 
kibaekkimm profile image
Kibaek Kim

In my case, different cookieNames property.
because i just copied and paste code above.

Collapse
 
samuelgoldenbaum profile image
Samuel Goldenbaum • Edited

Returning a 404 for an unauthenticated user - surely this would be a 401/403. In your demo, SSR would just show a 404 which doesn't make any sense.

redirecting/or using res.end within getServerSideProps will result in the error: 'ERR_HTTP_HEADERS_SENT' so don't see how that works either.

Collapse
 
chrsgrrtt profile image
Chris Garrett • Edited

It's quite common to return a 404 on protected endpoints for an unauthed user - it makes it harder to "profile" an application from the outside. Github do this, for instance. Feel free to implement differently though, for instance redirecting to the sign in screen - it's just a demo afterall...

I'm using res.statusCode, res.send inside getServerSidePros without issue; are you basing your assumption on a statically compiled next app?

Collapse
 
samuelgoldenbaum profile image
Samuel Goldenbaum

Thanks for the reply Chris.

There is an RFC for this issue. Take a look at the codesandbox demo and you will see

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

Maybe this is handled somehow in next-iron-session

Thread Thread
 
chrsgrrtt profile image
Chris Garrett

Thanks Samuel - that is very bizarre! I'm using this exact code successfully in a project at the moment, but you're right - it is an issue in the codesandbox demo... I'll do some digging.

Thread Thread
 
samuelgoldenbaum profile image
Samuel Goldenbaum

It seems to be an RFC at the moment and would be a great solution to be able to set headers - which could allow a redirect in getServerSidePros which would be great.

Currently, I have to use getInitialProps in a HOC and check if we SSR/client and do something like:

getInitialProps = async (ctx) => {
        const {token} = nextCookie(ctx);

        if (!token) {
            if (typeof window === 'undefined') {
                ctx.res.writeHead(302, {Location: '/login'});
                ctx.res.end();
            } else {
                Router.push('/login');
            }
        }

        return {};
    }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
sheptang profile image
Anıl Yarkın Yücel

Is it possible to use withIronSession in _app.jsx and pass the session:true|false to pageProps to wrap around each and every possible page in an easier way? That being said, it'd be inside the function App({ Component, pageProps }){.... Please tell me "YES", I need this answer and how :')

Collapse
 
akanshsirohi profile image
Akansh Sirohi

Very great, simple and useful example, but am not able to understand that how we could write a decorator/HoC that wraps getServerSideProps and performs the session validation in a reusable way, can anyone here give an example of that related to this example here.

Collapse
 
_builtbyjay profile image
Jay Vincent

This is great, thanks Chris! And thanks for the introduction to next-iron-session

Collapse
 
jsbimra profile image
Jatinder Singh

Yes succinct and too the points ;) more words could be cutdown at what is it explanation blocks. :)