[express.js] refreshToken

김민재·2024년 4월 2일

express.js

목록 보기
16/39

accessToken의 문제점

  • accessToken을 새로 생성해도 전에 생성했던 accessToken으로 이용이 가능해진다.

    이렇게 되면 하나의 토큰을 탈취하면 탈취한 토큰으로 계속 요청이 가능해진다.

    • 유효시간을 줄이면 되지만, 시간을 짧게하면 자주 토큰을 생성해야 한다.

refreshToken

  • 위와 같은 문제점을 보완하기 위해서 사용하게 된다.

  • jwt를 이용해서 발급 가능 하며, 주로 accessToken의 유효시간은 짧게 하고, refrestToken의 유효시간은 길게 해준다.

    그래서 accessToken의 유효시간이 다 지나면 refreshToken을 이용해서 새로운 accessToken을 발급해준다.

    accessTokenrefrestToken
    Access Token은 리소스에 접근하기 위해서 사용되는 토큰Refresh Token은 기존에 클라이언트가 가지고 있던 Access Token이 만료되었을 때 새로 발급하기 위해 사용되는 토큰

    token 발급되는 순서

    1. 사용자가 로그인을 시도한다.
      • 서버에서는 로그인 회원을 DB에서 찾는다. 또한 아이디와 비밀번호가 맞는지 확인한다.
    2. 로그인이 완료되면 AccessToken과 RefreshToken이 함께 발급된다.
      • 회원 DB에 일반적으로 RefreshToken을 저장한다.
    3. 사용자가 RefreshToken을 안전한 장소에 보관한 후, 서버에 요청을 보낼 때 AccessToken을 헤더에 실어 요청을 보낸다.
    4. AccessToken이 유효하면 요청한 데이터를 보내준다.
    5. AccessToken이 유효기간이 만료되었으면 에러를 보낸다.
    6. 사용자는 RefreshToken을 서버로 보내며 다시 AccessToken을 요청한다.
    7. 서버에서는 사용자가 보낸 RefreshToken과 DB에 저장되어 있는 RefreshToken을 비교한다. token이 동일하지 않고, 유효기간이 지났다면 새로 RefreshToken과 AccessToken을 새로 발급한다.

RefreshToken 발급하는 방법

  1. login 경로에 accessToken과 refreshToken을 생성해주고 cookie에 refreshToken을 담아준다.
let refreshTokens = [];

app.post("/login", (req, res) => {
  const username = req.body.username;
  const user = { username };

  // jwt를 이용해서 Token 생성하기 payload + secret
  const accessToken = jwt.sign(user, secretKey, { expiresIn: "30s" });
  const refreshToken = jwt.sign(user, refreshSecretKey, { expiresIn: "1d" });

  // 현재 db연결을 안 해서 배열에 담아둔다.
  refreshTokens.push(refreshToken);

  res.cookie("refershToken", refreshToken, {
    httpOnly: true,
    maxAge: 24 * 60 * 60 * 1000,
  });

  res.json({ accessToken });
});
  • refershToken의 key는 accessToken의 key와 다르게 해줘야한다.
  • accessToken의 유효기간은 30초, refreshToken의 유효기간은 하루로 정해줬다.
  • res.cookie를 이용해 refreshToken 변수에 refreshToken을 담아준다. 이때 httpOnly: ture를 해주는 이유는
    • javascript를 이용해서 탈취하거나 조작할 수 없게 만들어줘야한다.(XSS Cross Site Scripting 공격)
  1. login이 성공했으면 cookie에 refreshToken이 담기게 된다.

  2. accessToken을 이용해 유효기간이 30초인지 확인을 해준다. 만약 유효기간이 지났는데 데이터를 받아오려고 하면 Forbidden 에러가 나온다.

  3. accessToken의 유효기간이 만료되었으면, refreshToken을 이용해서 accessToken을 생성해준다.

  • 쿠키에 refreshToken이 담겨있으면, 알아서 accessToken을 교체해준다.

4-1. cookie를 받아오는 방법은 cookie-parser 모듈을 이용해야한다.

  • npm i cookie-parser
    const cookieParser = require("cookie-parser");
    app.use(cookieParser());
  • 미들웨어로 실행을 해줘야한다. 그리고 req.cookies를 이용하면 cookie에 담긴 refreshToken을 가져올 수 있다.

4-2. refreshToken을 이용해 accessToken을 다시 가져오도록 하는 경로와 함수를 만들자.

app.get("/refresh", (req, res) => {
  const cookies = req.cookies;

  if (!cookies?.refershToken) return res.sendStatus(403);

  const refreshToken = cookies.refershToken;

  if (!refreshToken.includes(refreshToken)) {
    return res.sendStatus(403);
  }

  jwt.verify(refreshToken, refreshSecretKey, (err, user) => {
    if (err) return res.sendStatus(403);

    const accessToken = jwt.sign({ username: user.username }, secretKey, {
      expiresIn: "30s",
    });
    res.json({ accessToken });
  });
  • req.cookies를 이용해 cookies 변수에 담아준다.
  • cookies에 refreshToken이 담겨있지 않다면 Frobidden 에러를 띄운다.
  • cookies.refreshToken을 refreshToken 변수에 담아둔다.
  • refreshToken이 없으면 Forbidden 에러를 띄운다.
  • jwt.verify()를 이용해 accessToken을 다시 보내준다.

profile
개발 경험치 쌓는 곳

0개의 댓글