Auth with JWT+Cookie

Jayant - Jul 28 - - Dev Community

What

Cookies are small piece of data sent from a server and is stored in user's computer. They are basically used to store info, just like localStorage.

Usage

  • Used for authentication and accessing protected routes.
  • It can store user preferences like such as language preference, theme etc.
  • Used for tracking user behaviour & site he/she visits, on the basis of that advertisements are showns.

BUT WHY NOT USE LOCALSTORAGE ?

  1. For Every Request we don't have to explicitlt send the authorization hedears, cookies are sent by default.
  2. Cookies have expiry date attached to them.
  3. We can restrict cookies to be only send sent when certain conditions are match.

Types of Cookie
Cookies

Properties of Cookie
Cookies

CSRF Attack
Cross site request forgery attack is an security attack where attacker tries tries to perform an action on a site where they are authenticated without user consent.
For Ex - You are authenticated to a bank site and attacker creates a malicious site which has links that sent transfer money request to bank website.

To Prevent this SameSite attribute is introduced.
This attribute has 3 values.

  1. None - cookie can sent on cross-origin requests.
  2. Lax - Default, cookie can be sent on cross-origin requests, but there are some conditions. For Ex - Only for GET method.
  3. Strict - Not sent on Cross-origin request.

How

Backend Code

import express from "express";
import cookieParser from "cookie-parser";
import cors from "cors";
import jwt from "jsonwebtoken";

const app = express();
const PORT = 3000;
const JWT_SECRET = "mysecret";

// Cookie sent over the HTTP request in the Cookie header will be in the form of string containing 2-3 key value pair
// cookie parser will parse the cookie header and convert it into an object and made it available in the req.cookies.
app.use(cookieParser());
// parses the JSON Data in body of the request and make it available in the req.body
app.use(express.json());
app.use(
    cors({
        origin: "http://localhost:5173",
        //credentials: true will allow requests to include cookies ,Headers and other credentials
        credentials: true,
    })
);

app.post("/signin", (req, res) => {
    const { email, password } = req.body;

    //  store it in the DB get the ID
    const token = jwt.sign(
        {
            id: 1,
        },
        JWT_SECRET
    );

    // It will set a cookie in the browser with the name token and value as the token
    res.cookie("token", token);
    res.json({ message: "Logged In" });
});

app.get("/user", (req, res) => {
    const token = req.cookies.token;
    const validatedData = jwt.verify(token, JWT_SECRET);

    // get the user data from the DB Based on ID.

    res.send({ validatedData, email: "" });
});

app.post("/logout", (req, res) => {
    res.clearCookie("token");
    res.send("Logged Out");
});

app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Frontend Code

import { useState } from "react";

const SignIn = () => {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");

    const handleLogin = async (e: any) => {
        e.preventDefault();
        const res = await fetch("http://localhost:3000/signin", {
            method: "POST",
            body: JSON.stringify({
                email,
                password,
            }),
            //If the server sets a cookie (such as a session cookie or authentication token) in the response to the POST request,
            //the browser will only store and send this cookie with future requests if credentials: "include" is specified.
            credentials: "include",
        });

        const data = await res.json();
        console.log(data);
    };

    return (
        <div>
            <input
                type="text"
                value={email}
                onChange={(e) => {
                    setEmail(e.target.value);
                }}
            />
            <input
                type="text"
                value={password}
                onChange={(e) => {
                    setPassword(e.target.value);
                }}
            />
            <button onClick={handleLogin}>Submit</button>
        </div>
    );
};

export default SignIn;

// Accessing protected Routes
fetch("http://localhost:3000/user", {
    method: "GET",
    credentials: "include",
}).then((res) => {
    res.json().then((data) => {
        console.log(data);
    });
});
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .