Lessons I learned when dealing with Security with Next Auth and MongoDB. Also applies to any JWT authentication system, but the code samples will use MongoDB-like queries + Next Auth functions.
JWT Principals
When using JWT's, these are some principles to keep in mind:
Keep pertinent data that is used frequently in the application within a JWT token. Think profile image, name, etc. This way you will not need to refetch any user data within your application.
Don't store sensitive data within a JWT token. This is dangerous!
All identifying information should be stored in the JWT token (like
userId
). This will come in later when we make requests to the server.
Securing Requests
When accessing any kind of data, security should always be top of mind to ensure that the user requesting or updating data has permission to do so. In order to accomplish this, WE MUST include the session in any of our protected database queries. With next-auth, this is handled for us. We can then access the userId from the session to ensure that the user can only query for resources that they are associated with. It would look something like this:
There are a couple of things to break down from the above code.
Note how we are getting
userId
from the session and not from the supplied input. This is because any bad actor can gain access to auserId
and simply query for other users protected resources. With a JWT session, we ensure that the user has not tampered with the token.We attach the
userId
at the end of the query. From a performance standpoint, the resource is immediately retrieved with the indexed_id
, and then verified that the returned result has the associateduserId
from the session. If they don't match, nothing is returned.
A similar pattern is used for any other type of request (CREATE, UPDATE, DELETE
).
Thinking Ahead - Collaborative App
Let's say that we want to introduce collaboration into our application in the future. How do we authenticate a user that was given permission to access a protected resource? In this case, we would allow userId
in the input and check to see if that user is on the allowed list. It would look something like this:
Other Considerations
Invalidating JWTs
Let's say you introduce a feature that requires the user to sign out. Maybe it's because you made a schema change or you want to put more information into the JWT token. You can do so by versioning JWTs and checking to see if the version of the JWT matches the application version.