JWT (JSON Web Token)
- 인증을 위한 정보를 특별한 저장소를 이용하지 않고, 전자 서명을 이용하여 확인하는 방법
JWT의 구성
- header : 토큰의 타입(jwt), 데이터 서명 방식
- payload : 전달되는 데이터
- signature : 헤더와 페이로드의 전자서명
- WEB Token, 데이터를 웹에서 사용하기 위한 스펙이므로 웹에서 문제없이 사용할 수 있는 문자열로만 구성된 base64 인코딩을 사용
- jwt 홈페이지에서 JWT Encode/Decode를 실행해 볼 수 있음.

JWT와 보안
- JWT의 payload는 단순히 정보를 base64 encode하며, decode 시 정보가 노출됨.
- 민감한 정보는 제외하고 토큰을 생성해야 함.
- 서버는 JWT를 생성할 때, 비공개키를 이용하여 서명을 한다. payload를 조작할 경우 서명이 일치하지 않기 때문에 인증 실패.
JWT 작동 방식
- 사용자 로그인
- 서버는 로그인 유저 정보를 JWT로 생성해서 클라이언트 저장
- 클라이언트는 전달받은 JWT를 이용하여 인증이 필요한 요청에 사용
JWT 사용 이유
- session은 기본적으로 웹 브라우저의 통신 스펙
- 모바일 앱 등, 웹 브라우저가 아닌 어플리케이션의 경우 이를 활용하기 부적합함
- jwt를 사용하면 어느 클라이언트에서나 동일한 방식의 사용자 인증을 구현 가능
cookie?
- 웹 서비스에서 사용하는 정보를 클라이언트에 저장하고, HTTP 요청 시 이를 함께 전송하여, 클라이언트 정보를 서버에 전달하는 기술
- session : 클라이언트 정보를 서버 측 저장소에 저장하고 사용
- cookie : 클라이언트 정보를 클라이언트(브라우저)에 저장하고 사용
JWT + cookie
- session을 사용한 유저 로그인의 경우 cookie에 session id 저장 . session store에서 유저 정보 가져오기
- jwt를 쿠키에 저장하는 경우, jwt로 요청 > 서명 확인 후 유저 정보 사용
- 데이터베이스 접근이 줄어서 효율적인 인증 구현 가능
JWT 로그인 구현
- 기존 세션으로 구현된 로그인을 비활성화
- 로그인 로직에서 JWT 생성 후 쿠키로 전달
- passport-jwt 패키지로 jwt 로그인 미들웨어 작성 및 사용
EX. passport-jwt 패키지 사용
const passport = require('passport');
setUserToken = (res, use) => {
const token = jwt.sign(user, secret);
res.cookie('token', token);
};
router.post('/', passport.authenticate('local'), (req, res, next) => {
setUserToken(res, req.user);
res.redirect('/');
});
const JwtStrategy = require('passport-jwt').Strategy;
const cookieExtractor = (req) => {
const {token} = req.cookies;
return token;
};
const opts = {
secretOrKey: secret,
jwtFromRequest: cookieExtractor,
};
module.exports = new JwtStrategy(opts, (user, done) => {
done(null, user);
});
passport.use(jwt);
EX. JWT Middleware
- JWT 미들웨어 추가
- JWT 토큰은 기본적으로 모든 요청에 포함
- 요청에 토큰이 있는 경우 로그인된 상태로 처리하기 위해, 모든 요청에 공통적으로 적용할 수 있는 미들웨어로 JWT 로그인을 추가
const passport = require('passport');
app.use((req, res, next) => {
if ((!req.cookies, token)) {
next();
return;
}
return passport.authenticate('jwt')(req, res, next);
});
jwt logout 구현
res.cookie('token', null, {
maxAge: 0,
});