Cookie-base is one of the primary uses for session management. It is easy to implement, suits smaller applications, and has a lower server load but may offer less security than others.
As cookies are susceptible to client-side security risks, the key to safeguarding user information from unauthorized access is to carefully encrypt the sensitive data before storing it in the cookie. This way, even if a cookie is stolen, the data inside remains unreadable.

What is NodeJS Crypto?

The Node.js crypto module is a built-in module that provides a variety of cryptographic functions for Node.js applications, which are written in JavaScript. It provides a collection of cryptographic functionality like creating hashes, signing and verifying messages, and encrypting and decrypting data. These functions can be used to perform different types of encryption, decryption, signing, and hashing operations.

How to use it?

1. Create a NextJS project
Let's start by creating a simple NextJS project by running the following command:

npx create-next-app@latest nextjs-sample-project

The folder structure will be like:

my-app/
├─ node_modules/
├─ public/
├─ app/
│ ├─ api/
│ │ ├─ auth/
│ │ │ ├─ route.js
│ ├─ lib/
│ │ ├─ utils.js
│ ├─ actions.js
│ ├─ layout.jsx
│ ├─ globals.css
│ ├─ page.jsx
├─ .gitignore
├─ package.json
├─ README.md
├─ .env.local

2. Create an encrypt and decrypt function using the Crypto module

First, in the .env.local file, add a secret key like CRYPTO_SECRET="my_secret_key" and this key will be used to create a crypto key.
Now, we start to create the encrypt and decrypt function as a utility in app/lib/utils.js.

Create a function that returns the "cipher" and "decipher" object

We use crypto method createHash("sha256") to create a sha256 hash, then use update(String(process.env.CRYPTO_SECRET) to update our CRYPTO_SECRET key as hash data, and then we use digest("base64") to return the hashed value as base64 string, finally we cut the base64 string to match our key length (32 bytes and 16 bytes lengths).

Create an encrypted data function

This function will accept the plaintext content, and then use a cipher object to encrypt and return encrypted content.

Create a decrypted data function

This function will take the encrypted content, and then use a decipher object to decrypt and return decrypted plaintext content.

Note: The encryption key and the initialization vector should be the same when encrypting and decrypting content.

3. Create "Authentication" API

Next.js has support for API Routes, which let us easily create an API endpoint as a Node.js serverless function. We'll use this feature to create a sample login API, then when the user login successfully, the user's session data will be encrypted and placed in the cookie.

First, we'll create a sample API route call api/auth to verify user login.

Next, we'll create a file called actions.js in the root folder and add the "use server" directive at the top of it. All functions within the file will be marked as Server Actions that can be reused in both Client and Server Components.

Now, inside the function login(), we'll get the user's data from the API response, encrypt it using the encrypt function that we'd made before, and then put it into the cookie. The completed code is the same as below (lines 18~31).

From now on, every time a user logs in successfully to our app, their session data will be encrypted and stored in the cookie.

4. Make some "UI" 

Now, open app/page.jsx and make a simple form to request our login API.

We also declare a handleSubmit function to take the value from the form and send it to request API.

5. Testing our app

Open the browser, the session cookie (Application > Cookies  in Dev Tools ) will be empty if the user has not logged in yet. After the user is logged in successfully, the session cookie with the encrypted value will be present.

 

The login session is now stored in the Cookies, it can be used in the middleware.js to do an Authorization or be used on another component by calling the Next cookies() function.

Conclusion

NodeJS supports a built-in module called Crypto that can easily help us encrypt and decrypt data without using a third-party library. And, if you select cookie-based sessions for your project session management, make sure you protect the user's session data carefully before storing it in cookies.

References

  • https://nextjs.org/docs/app/building-your-application/authentication#session-management
  • https://habtesoft.medium.com/encrypt-data-on-nodejs-e0a45c67c772
  • https://nodejs.org/api/crypto.html
  • https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations
  • Image source: https://unsplash.com/photos/brown-cookies-on-white-plastic-pack-YDvfndOs4IQ?utm_content=creditShareLink&utm_medium=referral&utm_source=unsplash

Leave a comment

*