Home > other >  Next-auth (JWT) logging sessions
Next-auth (JWT) logging sessions

Time:04-24

According to Next-auth documentation as we are using credentials provider to connect to our users collection for usernames and passwords Next-Auth does not use the session database to check if a session is active.

If you use a custom credentials provider user accounts will not be persisted in a database by NextAuth.js (even if one is configured). The option to use JSON Web Tokens for session tokens (which allow sign in without using a session database) must be enabled to use a custom credentials provider.

I am wanting to add a _middleware that will allow me to store and check that the latest JWT sessions inside our session database matches the latest one that the user is currently using.

Reason being is that if I have two devices technically I would be able to login on both devices and at the moment their is no real way to discern if the user from PC2 is also login on PC1.

So my theory and not sure if this will work is to add the following.

callbacks: {
        jwt: async ({ token, user }) => {
          console.log("running JWT - because of custom login")
            user && (token.user = user)
            
            (ADD CODE HERE TO SAVE TOKEN & CHECK IF TOKEN IS LATEST TOKEN   VALID - INSIDE SESSION DATABASE)

            (IF OLD-TOKEN IS NO LONGER VALID OR THE LATEST TOKEN LOG THE USER OUT)

            console.log("TOKEN IS "  JSON.stringify(token))
            return token
        },
        session: async ({ session, token, user }) => {
            console.log(JSON.stringify(session)  " / "  JSON.stringify(token)  "/"  JSON.stringify(user));

            
            session.user.tokenID = token //ADD CODE HERE TO SAVE TOKEN TO SESSION COOKIE

            session.user = user
            return session
        }
      },

Then if I create a middleware that checks this tokenID and matches it with the session database and if it is the latest result from said user.

For example.

Say PC1 (user1) login here

{
_id: 1
tokenID: 918171-918171-81716-0887
userid: 00-00-00-001
expire: "2022-05-23T12:47:04.593Z"
}

But then PC2 also (user1) login again and created a new session

{
_id: 2
tokenID: 71888-651777-616666-0117
userid: 00-00-00-001
expire: "2022-05-24T12:47:04.593Z"
}

What I would need the middleware to do (which a simple mongodb query could do) is check if their is an older session stored for the same userID if so then logout from PC1.

Now there are a few things that I can see going wrong with this idea.

  1. Other Provider Sessions (which use session DB) making it harder to validate
  2. Every time you call the signup page or session it seems to re-run the JWT section - which in theory is fine, as we could use a findOne Update function which if token is in session then just update the expiry - however that would cause say PC1 refreshes after PC2 logged in then PC1 expire time might be longer then PC2 expire time (but a simple sort function would allow us to see if the ID was older then PC2 if so logout).
  3. JWT changes token every time you reload the page

How would this help privacy and the user data?

  • By not storing the user details inside a session cookie we would not be exposing the data to hackers or other plugins like FB or Google as the user data would only be linked to a token ID. Which to request the user data you would have to make sure the tokenID was valid first and then be allowed to fetch user data.

I understand that Next-Auth may not want too do this, and this is why I ask the question what is the best practice to do what I am wanting to achieve.

CodePudding user response:

This answer is based on the confirmation that the issue is that you want to be able to only have users able to be signed in to one computer/device at time and that you are using usernames and passwords to authenticate them.

In that scenario you also need to have a database that records a token in each JWT issued. It is not possible to solve for that problem without a database.

Here is how you can solve for it it using JWT and a database:

  • On every new sign in, you would need to use the jwt callback to add something like a UUID to each JWT and then record that UUID , the User ID and the time the JWT expires in a database.
  • In that callback, if there are other entries in the database for the same User ID you should mark them as invalid (or delete them from the database).
  • Everytime an existing JWT is read in that same callback you would need to check to see if the UUID in the database was still valid (i.e. still exist / doesn't point to a UUID that corresponds to a JWT flagged as expired) and if it is no longer valid, don't return a valid JWT.
  • You might also want to add special handling in the session callback that does something similar to improve the user experience by gracefully handling it in the User Interface of the computer they are being signed out of.

Effectively this has all the downsides of a JWT with all the downsides of a session database (although there are niche cases where this is a preferable approach).

I would not recommend using usernames and passwords or limiting users to only being able to sign in to one computer at at time, however given those unusually specific constraints (which also necessitates a solution that has a negative impact on performance) you may want to consider a different authentication solution and/or think how else you could address the underlying need this is trying to address (and if it's worth the cost and complexity).

  • Related