2023.05.15 refresh token

이무헌·2023년 7월 21일
0

node.JS

목록 보기
5/10
post-thumbnail

1.refresh token이란?

1.이용자가 로그인 시도를 하고
2.서버에서 이용자를 확인하고 입장권을 발급해주고
JWT 토큰 인증정보를 payload에 할당하고 생성
3.생성한 토큰을 클라이언트에 반환해주고 클라이언트는 이 입장권을 가지고 있는다.
4.클라이언트가 서버에 요청을 할 때 이 입장권도 같이 보내서 요청을 시도한다.
5.서버는 요청을 받아서 그 입정권이 유효한지 확인하고 유효한 입장권이면 요청을 처리하고
  요청에 대한 응답을 해준다.
6.입장권이 정상적인지 확인하고 썩었는지 변조가 되었는지 (변조가 되었고 썩었으면 다시 재로그인 시킨다.)
  (입장권 새로 산다.)

refresh token을 같이 사용하면
Access token만 사용하면 인증 보안이 취약할 수 있어서 다른사람이 Access token을 탈취했을 때
토큰의 유효기간이 끝날 때 까지는 막을수가 없다... 그래서 유효기간을 짧게 주고 짧게 주면
로그인을 계속해야하는 번거로움이 생기고(사용자가 이용하기 힘들다.) Refresh token의 유효기간을 길게 주고
Access token의 유효기간을 짧게 주어서 너무 어려운 개념은 아니고... 토큰 두개 씀.
Refresh token은 유효기간을 길게 주고 Access token이 유효기간이 끝났을 때 밟급해주는 역할만 하면 된다.

Access token과 refresh token을 같이 사용한 인증 방식
1.클라이언트가 로그인
2.서버에서 사용자를 확인하고 입장권 권한 인증 정보를 payload에 할당하고 생성
3.Refresh token을 만들어서 데이터베이스에 저장해두고 2개의 토큰 전부 클라이언트에 전달해준다.
4.클라이언트도 두 토큰을 가지고 있고
5.클라이언트가 요청을 할 때 Access token을 전달해서 요청한다.
6.서버는 전달받은 토큰을 확인하고 decoding해서 Access token을 디코드 해서 사용자 정보를 확인하고
7.토큰이 정상적인지 확인(썩은 토큰인지 아닌지)
8.변조된 토큰이면 새로 로그인 시킬 수 있게 한다.
9.만약에 날짜가 지난 토큰이면 refresh token으로 다시 재발급 해준다.

쉽게 말해서 엑세스 토큰은 우리가 사용하는 그대로이고 refresh token만 추가되었는데 Access token의 발급 용도로만 알고있자.

2.Token발급

  • 로그인시 토큰 발급(전체 코드)
    // 로그인
    exports.Login = async (req, res) => {
      const { user_id, user_password } = req.body;
      try {
        const data = await userSelect(user_id);
        // 유저 조회가 되었다면, option chaning
        if (!data?.user_id) {
          return res.send("id없음");
        }
        if (data.user_pw !== user_password) {
          return res.send("비밀번호 틀림");
        }
    
        // 여기까지 통과하면 로그인 성공
        // access token 발급
        const accessToken = jwt.sign(
          {
            user_id: data.user_id,
            mail: "dddd",
            nick: "zero",
          },
          process.env.ACCESS_TOKEN_KEY,
          {
            expiresIn: "5s",
          }
        );
        // refresh token 발급
        const refreshToken = jwt.sign(
          {
            user_id: data.user_id,
          },
          process.env.REFRESH_TOKEN_KEY,
          {
            expiresIn: "50s",
          }
        );
        await userRefresh(user_id, refreshToken);
        req.session.access_token = accessToken;
        req.session.refresh_token = refreshToken;
        res.send({ access_token: accessToken, refresh_token: refreshToken });
      } catch (error) {
        console.log("login in userController", error);
      }
    };
  • 엑세스 토큰 밟급하는곳
    const accessToken = jwt.sign(
          {
            user_id: data.user_id,
            mail: "dddd",
            nick: "zero",
          },
          process.env.ACCESS_TOKEN_KEY,
          {
            expiresIn: "5s",
          }
        );
    • 저번에 했던 토큰 발급 코드이다.
  • Refresh Token 발급하는 곳
    // refresh token 발급
        const refreshToken = jwt.sign(
          {
            user_id: data.user_id,
          },
          process.env.REFRESH_TOKEN_KEY,
          {
            expiresIn: "50s",
          }
        );
    • 기존 엑세스 토큰보다 만료시간을 길게한다.
    • 이는 엑세스토큰이 만료돼도 refresh token으로 다시 발급하기 위해서이다.
  • req.session에 토큰을 저장하는 코드
    await userRefresh(user_id, refreshToken);
        req.session.access_token = accessToken;
        req.session.refresh_token = refreshToken;
        res.send({ access_token: accessToken, refresh_token: refreshToken });
    • userRefresh 함수
      exports.userRefresh = async (userId, refresh) => {
        try {
          await mysql.query("UPDATE users SET refresh=? WHERE user_id=?", [
            refresh,
            userId,
          ]);
        } catch (error) {
          console.log("userRefresh in userModel", error);
        }
      };
      • mysql에서 유저의 refresh 를 최신 토큰으로 업데이트 해준다.
      • 이 때, 만약 나중에 다른 브라우저(b)로 로그인할 경우 a와 b는 다른 refresh token을 가지고 있지만, mysql의 refresh 데이터는 나중에 로그인한 브라우저 b의 refresh값이 들어간다.
      • 그러므로 a에서 로그인하게되면 중복로그인이 뜬다.
    • 각 세션에 토큰을 저장한다.
  • 토큰 verify 하는 곳
profile
개발당시에 직면한 이슈를 정리하는 곳

1개의 댓글

comment-user-thumbnail
2023년 7월 21일

잘 봤습니다. 좋은 글 감사합니다.

답글 달기