액세스 토큰:
“이용자의 자격 확인 시 본인 인증을 목적으로 발급”
Simple Code: 사용자가 인증을 요청할 때 TOKEN 생성 시 사용한 개인키로 인증을 하므로 코드 구현이 용이하다.
Stateless: 서버가 죽었다가 되살아나도 같은 동작을 한다.
즉, 사용자가 인증되었는지 확인하지만 처음에 발급한 사용자인지는 확인하지 않습니다.
(질문: 그렇다면 최초 발급한 사용자인지 확인할 수 있는 방법이 있나요?)
위험성: 토큰 자체에 사용자 인증 정보가 모두 있기 때문에 도난 피해가 크다.
새로 고침 토큰:
“액세스 토큰을 얻기 위해 특정 사용자에게만 사용”
사용자가 아닌 서버가 사용자 인증 정보를 메모리 또는 별도의 데이터베이스에 유지 및 저장하므로 서버는 특정 토큰이 만료되기 직전에 저장된 토큰을 제거합니다. “사용자 인증은 언제든지 확인 가능” 하다.
액세스 토큰의 경우 사용자 인증 정보가 모두 포함되어 있기 때문에 인증 정보를 오래 사용할수록 협박의 위험이 높아집니다. OTP 서비스처럼 REFRESH TOKEN을 통해 ACCESS TOKEN을 발급받으면 토큰이 유출되더라도 피해를 최소화할 수 있기 때문이다.
새로 고침 토큰 발급
npm init -y
npm install express jsonwebtoken cookie-parser -S
Express 서버 작동 확인
// app.js
const jwt = require("jsonwebtoken");
const cookieParser = require("cookie-parser");
const express = require("express");
const app = express();
const port = 3002;
const SECRET_KEY = `HangHae99`;
app.use(cookieParser());
app.get("/", (req, res) => {
res.status(200).send("Hello Token!");
})
새로 고침 토큰 및 액세스 토큰 보냈다
최종 app.js 스크립트는 다음과 같습니다.
새로 고침 토큰을 먼저 발급한 다음 액세스 토큰을 발급하는 것이 중요합니다.
// app.js
const jwt = require("jsonwebtoken");
const cookieParser = require("cookie-parser");
const express = require("express");
const app = express();
const port = 3002;
const SECRET_KEY = `HangHae99`;
app.use(cookieParser());
app.get("/", (req, res) => {
res.status(200).send("Hello Token!");
})
// app.js
// Refresh token과 Access Token을 발급하는 API
let tokenObject = {}; // Refresh Token을 저장할 Object
app.get("/set-token/:id", (req, res) => {
const id = req.params.id;
const accessToken = createAccessToken(id);
//
const refreshToken = createRefreshToken();
tokenObject(refreshToken) = id; // Refresh Token을 가지고 해당 유저의 정보를 서버에 저장합니다.
// 서버에서 해당하는 refresh token에 대한 정보를 갖고 있지 않으면 token의 인증은 실패
res.cookie('accessToken', accessToken); // Access Token을 Cookie에 전달한다.
res.cookie('refreshToken', refreshToken); // Refresh Token을 Cookie에 전달한다.
// accessToken, refreshToken이라는 key로 2개의 쿠키를 발생
return res.status(200).send({ "message": "Token이 정상적으로 발급되었습니다." });
})
// Access Token을 생성합니다.
function createAccessToken(id) {
const accessToken = jwt.sign(
{ id: id }, // JWT 데이터 : api를 호출할때 받은 id 변수를 jwt 안에 삽입
SECRET_KEY, // 비밀키
{ expiresIn: '10s' }) // Access Token이 10초 뒤에 만료되도록 설정합니다.
return accessToken;
}
// Refresh Token을 생성합니다.
function createRefreshToken() {
const refreshToken = jwt.sign(
{}, // JWT 데이터, 아무것도 존재하지 않음.
SECRET_KEY, // 비밀키
{ expiresIn: '7d' }) // Refresh Token이 7일 뒤에 만료되도록 설정합니다.
// refresh token은 인증정보를 사용자가 가지고 있는게 아닌 서버에서 저장 및 관리
return refreshToken;
}
// Refresh token과 Access Token을 검증하는 API
app.get("/get-token", (req, res) => {
const accessToken = req.cookies.accessToken;
const refreshToken = req.cookies.refreshToken;
// 쿠키로부터 전달 받은 것들이 있느냐?
// 없다면 SET-TOKEN에서 아무것도 안된것
if (!refreshToken) return res.status(400).json({ "message": "Refresh Token이 존재하지 않습니다." });
if (!accessToken) return res.status(400).json({ "message": "Access Token이 존재하지 않습니다." });
// 사용자가 전달한 토큰이 정상적인 토큰인지를 확인하는 함수를 활용
// 우리가 발급한 토큰이 맞는지, 만료 여부를 검증
// 우리는 REFRESH TOKEN을 거쳐서 ACCESS TOKEN을 발급
// 궁금한 것 : 토큰이 존재하느냐? 맞느냐? 만료됐느냐? 어떻게 확인할 수 있을까?
const isAccessTokenValidate = validateAccessToken(accessToken);
const isRefreshTokenValidate = validateRefreshToken(refreshToken);
if (!isRefreshTokenValidate) return res.status(419).json({ "message": "Refresh Token이 만료되었습니다." });
// ACCESS TOKEN을 받기전에 REFRESH TOKEN을 먼저 받아야 하니까, 있는지 확인하고 새로 다시 발급받음
if (!isAccessTokenValidate) {
const accessTokenId = tokenObject(refreshToken);
if (!accessTokenId) return res.status(419).json({ "message": "Refresh Token의 정보가 서버에 존재하지 않습니다." });
const newAccessToken = createAccessToken(accessTokenId);
res.cookie('accessToken', newAccessToken);
return res.json({ "message": "Access Token을 새롭게 발급하였습니다." });
} // access token이 만료시간이 지나서 GET /get-token으로 하게되면 이 메시지가 뜰것
const { id } = getAccessTokenPayload(accessToken);
return res.json({ "message": `${id}의 Payload를 가진 Token이 성공적으로 인증되었습니다.` });
}) // access token이 만료시간이 지나기 이전에 GET /get-token으로 하게되면 이 메시지가 뜰것
// Access Token을 검증합니다.
function validateAccessToken(accessToken) {
try {
jwt.verify(accessToken, SECRET_KEY); // JWT를 검증합니다.
return true;
} catch (error) {
return false;
}
}
// Refresh Token을 검증합니다.
function validateRefreshToken(refreshToken) {
try {
jwt.verify(refreshToken, SECRET_KEY); // JWT를 검증합니다.
return true;
} catch (error) {
return false;
}
}
// Access Token의 Payload를 가져옵니다. 역할 ????????
function getAccessTokenPayload(accessToken) {
try {
const payload = jwt.verify(accessToken, SECRET_KEY); // JWT에서 Payload를 가져옵니다.
return payload;
} catch (error) {
return null;
}
}
app.listen(port, () => {
console.log(port, '포트로 서버가 열렸어요!');
})
더 알아보기
- 액세스 토큰과 새로 고침 토큰의 차이점은 무엇입니까?
- 갱신 토큰이 도난당한 것을 발견했을 때 서버는 어떻게 반응해야 합니까?
- 여권 라이브러리란 무엇입니까?
- OAuth란 무엇입니까?
서버 인증 2부(Access Token + Refresh Token) – Grabs Blog(tistory.com)
서버인증 2부(액세스토큰 + 리프레시토큰)
안녕하세요! 이전 포스트에서는 세션/쿠키 인증과 토큰 기반 인증(주로 JWT)에 대해 알아보았습니다. 앱, 웹 또는 서버를 개발할 때 사용해야 하는 권한 부여는 매우 중요합니다.
tansfil.tistory.com
(WEB) Access Token & Refresh Token 원리 (feat. JWT) (tistory.com)
(WEB) Access Token & Refresh Token 원리 (feat. JWT)
Access Token과 Refresh Token 이번 포스팅에서는 기본적인 JWT 방식의 인증(보안) 강화 방식인 “Access Token과 Refresh Token” 인증 방식에 대해 알아보도록 하겠습니다. 먼저 JWT(Json Web Token)에 익숙하지 않은 독자를 위해:
inpa.tistory.com
![[알고리즘이론] 파이썬 자료구조 [알고리즘이론] 파이썬 자료구조](https://file.foodle.kr/wp-content/plugins/contextual-related-posts/default.png)