Soufiane
Soufiane

Reputation: 160

I want to implement a sessions management system using Next-Auth

I want to implement a manage sessions system, so the user can logout all sessions when he change password.

1- when the user login I will store his session into user sessions array:

enter image description here

2- I'll check if the current session is stored in database, if not I'll log him out.

3- I want to add a "logout all sessions" button that logout all except for current session.

but I don't know how to start, because all I have when user login is:

{
  user: { uid: '61a53559b7a09ec93f45f6ad' },
  expires: '2021-12-30T16:34:58.437Z',
  accessToken: undefined
}
{
  user: { uid: '61a53559b7a09ec93f45f6ad' },
  iat: 1638290097,
  exp: 1640882097,
  jti: '2fc85541-eb9b-475e-8261-50c874f85b51'
}

my [next-auth].js :

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import mongoose from "mongoose";
import { compare } from "bcrypt";
import { User } from "../auth/signup"

export default NextAuth({
    //configure json web token
    session: {
        strategy: "jwt",
        maxAge: 30 * 24 * 60 * 60,
        updateAge: 24 * 60 * 60,
    },
    providers: [
        
        CredentialsProvider({
            async authorize(credentials){
                //connect to database
                const client = await mongoose.connect(process.env.DB_URI);
                //search for user using email or username
                const result = await User.findOne({$or: [{email: credentials.username}, {username: credentials.username}]});
                //if not found
                if(!result){
                    client.connection.close();
                    throw new Error("Incorrect username or password.");
                }
                const checkPassword = await compare(credentials.password, result.password);
                //of password doesn't match
                if(!checkPassword){
                    client.connection.close();
                    throw new Error("Incorrect username or password.")
                }
                
                client.connection.close();

                if(!result.emailVerified.verified){
                    client.connection.close();
                    throw new Error("Please verify your email adress.") 
                }

                return {
                   uid: result._id
                };
            }
        }),
    ], 
    callbacks: {
        async jwt({ token, user, account }){
            if (account) {
                token.accessToken = account.access_token
            }

            user && (token.user = user)
            return token
        },
        async session({ session, token }){
            session.user = token.user;
            session.accessToken = token.accessToken;
            
            return session;
        }
    }

});

Upvotes: 2

Views: 2235

Answers (1)

Soufiane
Soufiane

Reputation: 160

I created a sessions array for each user, when the user signs in, I generate a random hash key and save it to this array (you can add custom properties such as IP, time.. etc), and then save this hash to cookies, then I added a request in getServerSideProps

sessions array

export async function getServerSideProps(context){

    const {data: isAuthenticated} = await axios.get(`${process.env.WEB_URI}/api/auth/verify/session`, {
      headers: {
        cookie: context.req.headers.cookie
      }
    });

/api/auth/verify/session.js

export default async function session(req, res){

    if(req.method === "GET"){
        const session = await getSession({req: req});
        if(!session){
         return res.send(false);
        }

        mongoose.connect(process.env.DB_URI, {useUnifiedTopology: true} , async function(error) {
            if(!error){    
                const user = await User.findOne({uid: session.user.uid}, {_id: 0, sessions: 1});
                
                if(!user){
                    return res.send(false);
                }

                const userSession = user.sessions;
                if(userSession.length > 0){
                    const tokens = userSession.map((session => session.token));
                    
                    if(tokens.includes(session.user.token)){
                        res.send(true);
                    }else{
                        res.send(false);
                    }
                }else{
                    res.send(false);
                }
            }
        });
  }
}

finally

 if(props.isAuthenticated === false){
        signOut();
    }

Upvotes: 1

Related Questions