본문으로 바로가기

JWT 토큰 쿠키에 저장/삭제

category 개발/JS 2022. 1. 4. 00:30

설치
$ yarn add jsonwebtoken dotenv
.env 파일
# jsonwebtoken
JWT_KEY = 12345678901234567890123456789012345678901234567890123

KEY 값은 다음 사이트를 참고해서 생성할 수 있다.

https://www.codegrepper.com/code-examples/javascript/random+jwt+secret+key+generator 

 

random jwt secret key generator Code Example

node -e "console.log(require('crypto').randomBytes(256).toString('base64'));"

www.codegrepper.com

users.js 파일
require('dotenv').config(); // .env variable
const jwt = require('jsonwebtoken');
const { auth } = require('../middleware/authMiddleware');
...
router.post('/login', (req, res, next) => {
    const reqUsername = req.body.username;
    const reqPassword = req.body.password;

    if (!isAdmin(reqUsername)) {
        return res.send(' <script> alert("admin의 로그인만 가능합니다."); location.href="/users/login"; </script> ');
    }

    const sql = 'SELECT * FROM users WHERE username = ? ';
    const params = [ADMIN_ID];
    db.query(sql, params, async (err, rows, fields) => {
        if (err) return res.send(err);

        const password = await makePasswordHashed(reqPassword, rows[0].salt);
        if (rows[0].password === password) {
            // JWT 생성
            token = jwt.sign(
                {
                    type: 'JWT',
                    id: 'admin',
                },
                JWT_KEY,
                {
                    expiresIn: '60m',
                }
            );

            res.cookie('user', token, {
                httpOnly: true,
            });

            return res.send(' <script> alert("로그인 성공"); location.href="/"; </script> ');
        } else return res.send(' <script> alert("비밀번호가 다릅니다."); location.href="/users/login"; </script> ');
    });
});
...

JWT 생성 사용 방법은 payload, secretOrPrivateKey, [optinos, allback] 세 부분으로 나뉜다. payload는 실제 데이터를 싣는 공간이다. type에 JWT를 id에 admin 값을 싣었다. 보안키로 dotenv로 환경변수를 저장한 변수 JWT_KEY를 사용했다. 옵션으로 만료시간을 60분으로 설정했다.

jwt.sign(payload, secretOrPrivateKey, [options, callback])

만료 시간은 60, "2 days", "10h", "7d"의 형식으로 지정 가능하며 단위가 없으면 초 단위로 지정된다.

 

JWT 토큰은 선택에 의해 로컬 스토리지, 세션, 쿠키에 저장하는 방법을 선택한다. 장/단점이 서로 존재하므로 필요에 의한 방법을 선택하면 될 듯하다. res.cookie를 사용해 쿠키에 user 이름으로 token을 저장하는 과정에 옵션으로 httpOnly 설정을 추가했다. 이는 XSS 보안 취약점을 방지하기 위한 것이다.

middleware/authMiddleware.js 파일
require('dotenv').config();
const jwt = require('jsonwebtoken');
const JWT_KEY = process.env.JWT_KEY;

exports.auth = (req, res, next) => {
    // 인증 완료
    try {
        // 요청 헤더에 저장된 토큰(req.headers.authorization)과 비밀키를 사용하여 토큰을 req.decoded에 반환
        // req.decoded = jwt.verify(req.headers.authorization, JWT_KEY);
        // 쿠키에 user 이름으로 JWT 저장
        req.decoded = jwt.verify(req.cookies.user, JWT_KEY);
        return next();
    } catch (error) {
        // 인증 실패
        // 유효시간이 초과된 경우
        if (error.name === 'TokenExpiredError') {
            return res.status(419).json({
                code: 419,
                message: '토큰이 만료되었습니다.',
            });
        }
        // 토큰의 비밀키가 일치하지 않는 경우
        if (error.name === 'JsonWebTokenError') {
            return res.status(401).json({
                code: 401,
                message: '유효하지 않은 토큰입니다.',
            });
        }
    }
};
미들웨어 사용 방법
router.get('/token', auth, (req, res, next) => {
    res.send(req.decoded);
});

/token 라우터에 auth 미들웨어를 사용해 디코더 된 값을 확인할 수 있다.

쿠키 삭제
router.get('/logout', (req, res, next) => {
    res.clearCookie('user');
    res.redirect('/');
});

쿠키 생성 및 삭제는 크롬 개발자 도구를 통해 확인 가능하다.

 

세부적인 내용은 jsonwebtoken npm 사이트에서 확인 가능하다.

https://www.npmjs.com/package/jsonwebtoken

 

jsonwebtoken

JSON Web Token implementation (symmetric and asymmetric)

www.npmjs.com