본문 바로가기

궁금해

토큰? (JWT?)

 

0. 토큰

서버 측에서 상태를 관리하는 세션과는 다르게,

토큰은 클라이언트 측에서 상태를 관리하는 방식이다.

 

토큰은 인증된 사용자에게 서버가 발급하는 암호화된 문자열로,

클라이언트는 서버와의 통신 시 이 토큰을 직접 전달하여 인증을 받는다.

 

토큰을 사용하면 서버는 클라이언트의 상태를 기억할 필요가 없고,

토큰 자체에 필요한 정보가 담겨 있기 때문에 별도의 세션을 사용할 필요도 없고,

서버는 토큰의 유효성만 검사하면 된다.

(정보를 담고있는 만큼, 당연히 세션보다는 용량이 크다.)

 

대표적인 토큰으로는 JWT가 있다.

 

1. JWT

 

JWT : Json Web Token

 

가장 중요한 기능은 위조 여부 확인에 있다.

JWT 비밀키를 모르면 변조가 불가능하다.

(내용은 비공개가 아니다.)

 

2. JWT 기본 구조

 

a. Header 헤더 : 토큰 유형, 암호화 알고리즘 정보

b. Payload 페이로드 : 실제 정보(등록된 클레임, 공개 클레임, 비공개 클레임)

c. Signature 서명

 

각 부분은 . 으로 구분된다. ( xxxxx.yyyyy.zzzzz )

 

페이로드는 암호화되지 않으므로 중요한 정보는 포함하지 않는 것이 좋다.

 

서명은 헤더와 페이로드를 결합하여 생성한 후, 비밀키나 공개키를 사용해 서명한 값이다.

서명은 JWT의 변조여부를 검증하는 데 사용된다.

 

3. JWT 사용법

 

a. 설치 : npm i jsonwebtoken

b. 서버의 토큰 전달 : JWT를 생성하여 클라이언트에 전달

// controllers/v1.js

const jwt = require('jsonwebtoken');
const { Domain, User, Post, Hashtag } = require('../models');

exports.createToken = async (req, res) => {
  const { clientSecret } = req.body;
  try {
    const domain = await Domain.findOne({
      where: { clientSecret },
      include: {
        model: User,
        attribute: ['nick', 'id'],
      },
    });
    if (!domain) {
      return res.status(401).json({
        code: 401,
        message: '등록되지 않은 도메인입니다. 먼저 도메인을 등록하세요',
      });
    }
    // 토큰 생성
    const token = jwt.sign({
      id: domain.User.id,
      nick: domain.User.nick,
    }, process.env.JWT_SECRET, {
      expiresIn: '30m', // 30분
      issuer: 'nodebird',
    });
    // 토큰 전달
    return res.json({
      code: 200,
      message: '토큰이 발급되었습니다',
      token,
    });
  } catch (error) {
    console.error(error);
    return res.status(500).json({
      code: 500,
      message: '서버 에러',
    });
  }
};

 

c. 클라이언트의 토큰 전달 : Authorization 헤더에 포함하여 전달

d. 토큰 확인

// middlewares/index.js

const jwt = require('jsonwebtoken');

exports.verifyToken = (req, res, next) => {
  try {
    // req.headers.authorization를 process.env.JWT_SECRET 가지고 검증
    // 검증 통과하면, 복호화한 값을 return
    // 검증 오류있으면, catch로
    res.locals.decoded = jwt.verify(req.headers.authorization, process.env.JWT_SECRET);
    return next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') { // 유효기간 초과
      return res.status(419).json({
        code: 419,
        message: '토큰이 만료되었습니다',
      });
    }
    return res.status(401).json({
      code: 401,
      message: '유효하지 않은 토큰입니다',
    });
  }
};

 

'궁금해' 카테고리의 다른 글

response.json()?  (0) 2025.03.12
SPA? CSR? SSR?  (0) 2024.11.20