node.js/Json Web Token

jsonwebtoken

Hyunsoo_Kim 2024. 8. 11. 03:02

jsonwebtoken



Node.js 환경에서 JWT를 생성하고 검증하는 라이브러리

 

설치


npm install jsonwebtoken

 

토큰 생성


jwt.sign(payload, secretKey, [options])
const user = {
  email: "user1@gamil.com",
  nickname: "user1"
}

const option = {
  expiresIn: "1h"
}

jwt.sign(user, secreyKey, option)

1. option 인자에는 만료시간(expressIn), 발급자(issuer),  대상(audience)을 키와 값으로 가진 객체를 넣을 수 있다.

2. secretKey는 절대 노출되면 안되는 문자열 값으로, env파일에 보관하며 gitignore에 반드시 env파일을 추가해야 한다.

3. jwt.sign의 반환 값은 string 타입의 jwt 토큰이다.

 

토큰 유효성 검증


jwt.verify(token, secretKey, [options], callback)
const token = "// jwt토큰 값"

jwt.verify(token, secretKey, (error, decoded) => {
  if (error) {
    return res.status(403).send({ message: "error in verify" })
  }
  
  if (decoded) { decoded는 디코딩된 페이로드 객체
    decoded.userId === User._id
      ? console.log("Authentication succeeded");
      : console.log("Authentication failed");
  }
}

1. option 인자에는 sign 메서드와 같은 옵션을 넣을 수 있다.

2. 콜백함수의 첫번째 인자는 에러 객체, 두번째 인자는 JWT가 유효한 경우 디코딩된 페이로드를 포함하는 객체이다

verify의 반환 값

console.log(jwt.verify(token, secretKey);

1. 콜백함수를 넣지 않은 verify 메서드의 반환 값은 디코딩된 페이로드 객체이다.

2. 콜백함수를 넣은 verify 메서드는 비동기적으로 동작한다. 따라서 반환 값은 undefined이다. 비동기적으로 동작하긴 하지만 프로미스를 반환하는게 아니기 때문에 await으로 결과 값을 추출할 수 없다. 하지만 콜백함수의 두번째 인자에 디코딩된 페이로드 객체가 들어가기 때문에 콜백함수에서 페이로드를 처리할 수 있다.

 

회원가입, 로그인 구현


const express = require("express");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const { User } = require("../model/user.js");

const app = express();
app.use(express.json());

// 회원가입

app.post("/sign_up", async(req, res) => {
  const { email, password } = req.body;
  const isEmailExist = await User.findOne({ email });
  
  if (isEmailExist) {
    return res.status(409).send({ message: "given email is already exist" });
  }
  
  const hashedPassword = await bcrypt.hash(password, 10);
  const newUser = await User.create({ email, password: hashedPassword });
  
  res.status(201).send(newUser);
  }
)

// 로그인

app.post("/sign_in", async(req, res) => {
  const { email, password } = req.body;
  const user = await User.findOne({ email });
  
  if (!user) {
    return res.status(404).send({ message: "can not find with given email" });
  }
  
  const isPasswordCorrect  = await bcrypt.compare(password, user.password);
  
  if (!isPasswordCorrect) {
    return res.status(401).send({ message: "given password does not match" });
  }
  
  const payload = { email: user.email };
  const token = jwt.sign(payload, process.env.SECRET_KEY, { expiresIn: '1h' });
  
  res.status(200).send({ token });
  }
)