토큰의 등장 배경
세션 기반 인증은 서버에서 유저의 상태를 관리하기 때문에 서버 부하나 메모리 부족의 문제가 있다. 토큰 기반 인증은 이러한 세션 기반 인증의 한계를 극복하기 위해 고안 되었다.
레인보우 테이블솔트해싱의 목적은 데이터 그 자체를 사용하기 위해 원본 문자열을 알아내는데 있는 것이 아니라, 동일한 값의 데이터를 사용하고 있는지 여부만 확인하는 것이 목적이다. 따라서 복호화가 불가능한 것이 오히려 해싱의 이점이 된다.

무상태성 → 서버 증설에 용이하다. . 으로 나누어진 세 부분으로 구성되어 있다. → Header, Payload, Signature토큰 자체를 설명하는 데이터가 담겨있다.
{
"alg": "HS256",
"typ": "JWT"
}
전달하려는 내용물을 담고있는 부분
{
"sub": "someInformation",
"name": "phillip",
"iat": 151623391
}
Header + Payload + Secret key로 토큰의 무결성을 유지한다. 누군가 권한을 속이기 위해 payload를 변조해도 Secret을 정확하게 알지 못한다면 해당 요청은 올바르지 않은 토큰임을 알아낼 수 있다.
// HMAC SHA256 알고리즘을 사용한 경우 예시
HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);
무상태성 → 강제 만료 불가능Access Token과 Refresh Token 함께 사용한다.
Access Token : 접근을 위한 토큰 → 유효기간이 짧다. Refresh Token : 엑세스 토큰이 만료되었을때 새로운 액세스 토큰을 발급받기 위해 사용하는 토큰이다. → 유효기간 상대적으로 길다.module.exports = (req, res) => {
// 브라우저에서 쿠키를 가져온다.
// 쿠키에 토큰을 담았기 때문에 쿠키에서 토큰을 가져온다.
const { access_jwt, refresh_jwt } = req.cookies;
// 액세스 토큰이 있다면 유저 정보를 DB에서 조회하여 응답해준다.
if (access_jwt) {
// 유효한 키인지 확인하는 과정
const accessTokenPayload = verifyToken("access", access_jwt);
// 액세스 토큰이 유효하다면,
if (accessTokenPayload) {
// 유저정보 찾고
const exUser = {
...USER_DATA.find((user) => user.id === accessTokenPayload.id),
};
// 유저 정보 반환해준다.
delete exUser.password;
return res.send(exUser);
}
// -------- refresh-------- //
// 액세스 토큰이 없다면 리프레시 토큰을 확인해야한다.
// 즉 바로 404(Not found) 에러를 주면 안된다.
if (refresh_jwt) {
const refreshTokenPayload = verifyToken("refresh", refresh_jwt);
// 받아온 리프레스 토큰을 검증한다. 브라우저에서 넘어온 정보가 유효한가?
// 리프레시 토큰 검증이 실패했다면 에러를 준다.
if (!refreshTokenPayload)
return res.status(401).send("Not Authorized");
// 토큰 검증에 성공했다면 유저를 찾는다.
const exUser = {
...USER_DATA.find((user) => user.id === refreshTokenPayload.id),
};
// 유저를 찾지 못했다면 에러를 준다.
if (!refreshTokenPayload)
return res.status(404).send("Not Authorized");
// 유저를 찾은 경우에는 엑세스 토큰을 갱신해준다.
const cookieOption = {
domain: "localhost",
path: "/",
httpOnly: true,
sameSite: "none",
secure: true,
};
const { accessToken } = generateToken(exUser, false);
res.cookie("access_jwt", accessToken, cookieOption);
}
// 위 조건에 안걸리는 마지막의 경우는
// Access Token과 Refresh Token 모두 만료된 경우를 의미한다.
return res.status(401).send("Not Authorized");
}