본문 바로가기

Nodejs

Nodejs Express + JWT 토큰 발행 및 토큰 검증

반응형

프론트와 백엔드의 서버 분리로 인해 옛날옛날 처럼 세션방식으로 시스템에서 인증할 수 없다.

이를 해결 하기 위한 방법들 중 대표적인(제 생각) 방법이 토큰 인증 방식인 것 같다.

프로세스는 보통 

로그인 뷰 -> 로그인 요청 -> 토큰발행 -> 토큰 저장(쿠키 or 브라우저 스토리지) -> 페이지 이동 및 API 요청 시 토큰 체크

정도가 될 것 같다.

이 때, 서버쪽 작업 토큰발행, 토큰 체크를 간단하게 알아보려고 한다.

 

  1. 일단 먼저 입맛에 맞게 Nodejs Express App 을 만든다. 
  2. 기타 설정을 마쳤다면, 토큰 작업 테스트를 위한 패키지를 설치한다.
    npm install jsonwebtoken
  3. 본인이 원하는 URI 를 정의한다. 필자 같은 경우는 세 종류로 정의하였다.
    'use strict';
    
    const router = require('express').Router();
    const controller = require('./auth.controller');
    
    // 발행
    router.post('/token/issuance', controller.issueToken);
    
    // 재발행
    router.post('/token/reissuance', controller.reissueToken);
    
    // 인증
    router.post('/token/verification', controller.verifyToken);
    
    module.exports = router;
  4. 이 후 컨트롤러를 작성한다.
    'use strict'
    
    const jsonwebtoken = require('jsonwebtoken');
    const JWT_SECRET = 'sbjangTest';
    const ACCESS_TOKEN_EXPIRE = '5m';
    const REFRESH_TOKEN_EXPIRE = '6h';
    
    const verifyToken = (req, res, next) => {
        try {
            const clientToken = req.headers.access_token || req.query.access_token;
            const decoded = jsonwebtoken.verify(clientToken, JWT_SECRET);
            if (decoded) {
                res.status(200).json({
                    valid: true
                });
            } else {
                res.status(401).json({valid: false, error: 'unauthorized'});
            }
        } catch (err) {
            if (err.name === 'TokenExpiredError') {
                res.status(419).json({ valid: false, error: 'token expired' });
            } else {
                res.status(401).json({ valid: false, error: 'unauthorized' });
            }
        }
    };
    
    const issueToken = (req, res, next) => {
        const accessToken = jsonwebtoken.sign({
            user_id: 'sbjang',
            email: 'sbjang@test.com',
        }, JWT_SECRET, {
            expiresIn: ACCESS_TOKEN_EXPIRE,
            issuer: 'authUser',
        });
        const refreshToken = jsonwebtoken.sign({
            user_id: 'sbjang',
            email: 'sbjang@test.com',
        }, JWT_SECRET, {
            expiresIn: REFRESH_TOKEN_EXPIRE,
            issuer: 'authUser',
        });
    
        res.status(201).json({
            access_token: accessToken,
            refresh_token: refreshToken
        });
    };
    
    const reissueToken = (req, res, next) => {
        try {
            const refreshToken = req.headers.refresh_token || req.query.refresh_token;
            const decoded = jsonwebtoken.verify(refreshToken, JWT_SECRET);
            if (decoded) {
                const accessToken = jsonwebtoken.sign({
                    user_id: decoded.user_id,
                    email: decoded.email,
                }, JWT_SECRET, {
                    expiresIn: ACCESS_TOKEN_EXPIRE,
                    issuer: 'authUser',
                });
                res.status(201).json({
                    access_token: accessToken,
                    refresh_token: refreshToken
                });
            } else {
                res.status(401).json({ error: 'unauthorized' });
            }
        } catch (err) {
            if (err.name === 'TokenExpiredError') {
                res.status(419).json({ error: 'token expired' });
            } else {
                res.status(401).json({ error: 'unauthorized' });
            }
        }
    };
    
    module.exports = {
        verifyToken,
        issueToken,
        reissueToken
    };​

jsonwebtoken 패키지의 sign 을 통해 토큰을 발행받을 수 있으며, verify 를 통해 간단하게 토큰이 유효한지 체크할 수 있다.

 

※ 위는 단지 샘플 소스이고, 만약 정말 jwt와 같은 라이브러리를 쓰게된다면 sign 이나 verify 를 하기 위한 JWT_SECRET(시크릿키) 같은 경우는 프로퍼티 파일에서 관리하고 소스관리를 하지 않도록 해야할 것으로 보입니다..:)

 

참고소스

https://github.com/sbjang123456/blog/tree/main/nodejs-jwt-auth

 

GitHub - sbjang123456/blog

Contribute to sbjang123456/blog development by creating an account on GitHub.

github.com

 

 

반응형