๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
โœจ FrontEnd/๐Ÿ“… RhythMeet : ํ•ฉ์ฃผ์‹œ๊ฐ„ํ‘œ ํ”„๋กœ์ ํŠธ

[RhythMeet] ๋กœ๊ทธ์ธ - JWT ํ† ํฐ ์ธ์ฆ ๊ตฌ์กฐ ๊ฐœ์„ 

by ๋ฝ€์งœ๊ผฌ 2025. 10. 21.
728x90
๋ฐ˜์‘ํ˜•

์„œ๋ก 

JWT ํ† ํฐ.. ๋ง‰ ํ”„๋กœ์ ํŠธ๋ฅผ ์ ‘ํ•˜๋˜ 1-2ํ•™๋…„ ํ•™๋ถ€์ƒ ์‹œ์ ˆ์— ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ์ด๊ฑธ๋กœ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์–ด์„œ ๋‚‘๋‚‘๋Œ”๋˜์ ์ด ์žˆ๋‹ค.

๊ทธ๋•Œ๋Š” ์ด๊ฒŒ ๋ฌด์Šจ๋ง์ด์ง€ ๋„์ €ํžˆ ์ดํ•ด๋ฅผ ๋ชปํ•˜๊ณ  ๊ตฌํ˜„์„ ํฌ๊ธฐํ–ˆ์—ˆ๋Š”๋ฐ,

์ง€๊ธˆ์€ ์ด๊ฑธ ์ดํ•ดํ•˜๊ณ  ํ”„๋กœ์ ํŠธ์— ์ ์šฉ ์‹œ์ผฐ๋‹ค๋‹ˆ ์‹ ๊ธฐํ•œ ์ผ์ด๋‹ค. ๋งŽ์ด ์„ฑ์žฅํ–ˆ์Œ์„ ๋А๋‚€๋‹ค.


๋ถ€๋„๋Ÿฝ์ง€๋งŒ RhythMeet ๊ธฐ์กด์˜ ๋กœ๊ทธ์ธ ์ธ์ฆ ๋ฐฉ์‹์€ ๋ฌธ์ œ๊ฐ€ ์ข€ ๋งŽ์•˜๋‹ค.

๋ฐœํ‘œ ์‹œ๊ฐ„์— ๋งž์ถฐ์„œ ํ•œ๋‹ฌ์ด๋ผ๋Š” ์งง์€ ์‹œ๊ฐ„ ์•ˆ์— ์ตœ๋Œ€ํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ์–ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๋•Œ๋ฌธ๋„ ์žˆ์„๊ฒƒ์ด๋‹ค.

 

์–ด์จŒ๋“ , ์ด๋ฒˆ ๋กœ๊ทธ์ธ ์ธ์ฆ ๋ฐฉ์‹์„ ๋‚ด๊ฐ€ ๋ฆฌํŒฉํ† ๋งํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

์ œ๋Œ€๋กœ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋ณด๊ณ  ์‹ถ์—ˆ๋Š”๋ฐ ๋‚˜์•ผ ๋Ÿญํ‚ค๋น„ํ‚ค๋‹ค๐Ÿ€

๊ทธ๋Ÿฌ๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€ ํฌ์ŠคํŒ…ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.


๋กœ๊ทธ์ธ ์ธ์ฆ ๊ตฌ์กฐ

์šฐ์„  ๊ธฐ๋ณธ์ ์œผ๋กœ ์•ก์„ธ์Šค ํ† ํฐ / ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ํ•œ ์„ธํŠธ๊ฐ€ ์žˆ๊ณ 

๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ์ด์šฉํ•ด ์•ก์„ธ์Šค ํ† ํฐ์„ ๊ฐฑ์‹ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ์ ์ธ ์ด๋ก ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  JWT ํ† ํฐ์„ ์ฟ ํ‚ค์— ์ €์žฅํ•ด์•ผ ๋ณด์•ˆ์„ฑ์ด ์ข‹๋‹ค๋Š”๊ฒƒ๋„,

(์ด์ •๋„๋Š” ์•Œ๊ณ ์žˆ์—ˆ๋‹ค)

 

๊ทธ๋Ÿฌ๋ฉด ๊ธฐ์กด์˜ ์ฝ”๋“œ๋Š” ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ์„๊นŒ? ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์„๊นŒ?


๋ฌธ์ œ ์ƒํ™ฉ

๊ธฐ์กด์˜ ์„œ๋น„์Šค ๋กœ๊ทธ์ธ ์ธ์ฆ ๊ตฌ์กฐ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.

1. Access ํ† ํฐ๊ณผ Refresh ํ† ํฐ์„ ๋ชจ๋‘ ์‘๋‹ต Body๋กœ ์ „๋‹ฌ๋ฐ›๊ณ  ์žˆ์—ˆ๋‹ค.

2. ๊ทธ๋ฆฌ๊ณ  ์ด๋ ‡๊ฒŒ ์ „๋‹ฌ๋ฐ›์€ ํ† ํฐ์„ ํ”„๋ก ํŠธ์—์„œ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

3. RefreshToken์˜ ์œ ํšจ๊ธฐ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋ฌดํ•œ ๋กœ๋”ฉ ๋ฐ ๋กœ๊ทธ์•„์›ƒ์ด ๋ถˆ๊ฐ€ํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

4. ๋ฌผ๋ก  ๋ณด์•ˆ์ƒ์˜ ์ด์Šˆ๋„ ์žˆ์—ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด ์„œ๋น„์Šค ์ž์ฒด ์‚ฌ์šฉ์—๋„ ๋ฌธ์ œ๊ฐ€ ์žˆ๋˜ ์ƒํ™ฉ์ด์—ˆ๋‹ค.

(๋ฌดํ•œ๋กœ๋”ฉ..)

 

๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •

1. ๋ฉ˜ํ† ๋‹˜๊ป˜ ์งˆ๋ฌธ๋“œ๋ฆฌ๊ธฐ

ํ† ํฐ์„ ์ฟ ํ‚ค์— ์ €์žฅํ•˜๊ณ  ์‹ถ์—ˆ๋‹ค. ์ด๋Ÿด ๊ฒฝ์šฐ ๋ฐฑ์—”๋“œ์˜ ๊ตฌ์กฐ๋„ ๋ฐ”๊ฟ”์•ผ ํ•˜๋Š”๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ๊ธฐ์—,

์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝํ•˜๋ฉด ์ข‹์„์ง€ ๋ถ€ํŠธ์บ ํ”„ ์‹œ์ ˆ ๋ฉ˜ํ† ๋‹˜๊ป˜ ์—ฐ๋ฝ์„ ๋“œ๋ ธ๋‹ค.

 

header์— ๋‹ด์•„์„œ ๋ณด๋‚ด๋„๋ก ์ˆ˜์ •์„ ํ•ด์ค˜์•ผ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ฆฌํ”„๋ ˆ์‹œํ† ํฐ์€ ํ”„๋ก ํŠธ๋กœ ์ „๋‹ฌ์„ ํ•ด์ฃผ์ง€ ์•Š๊ณ , ๋ฐฑ์—”๋“œ ์ชฝ์—์„œ๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ๋‹ต๋ณ€์ฃผ์…จ๋‹ค.

๋‘๊ฐœ ๋‹ค ์ฃผ๋Š”๊ฒƒ์€ ๊ด€๋ฆฌ์ž ๊ถŒํ•œ์„ ์ฃผ๋Š”๊ฒƒ๊ณผ ๋™์ผํ•˜๋‹ค๊ณ ..

https://olrlobt.tistory.com/98

์ฐธ๊ณ ์ž๋ฃŒ๋„ ์ฃผ์…จ๋‹ค

 

๊ทธ๋ ‡๋‹ค. ๋‘˜๋‹ค body๋กœ ์ „๋‹ฌํ•˜๋ฉด ์•ˆ๋˜๋Š”๊ฒƒ์ด์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋กœ๊ทธ์ธ ๋ฆฌํŒฉํ† ๋ง ๋‹ด๋‹น ๋ฐฑ์—”๋“œ ํŒ€์›์—๊ฒŒ ์ด ์–˜๊ธฐ๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ๋…ผ์˜๋ฅผํ•˜์˜€๋‹ค.

2. ์„œ๋ฒ„ ๋กœ์ง ๊ฐœ์„ 

ํ•˜์—ฌ ๋ฐฑ์—”๋“œ ํŒ€์›์ด ๋กœ๊ทธ์ธ ๋กœ์ง ๊ตฌ์กฐ๋ฅผ ๊ฐœ์„ ํ•ด์„œ ์˜ค์…จ๋‹ค.

 

๋กœ๊ทธ์ธ์‹œ Access ํ† ํฐ๊ณผ Refresh ํ† ํฐ ๋ชจ๋‘ Body ๋กœ ์‘๋‹ต

->  ๋กœ๊ทธ์ธ์‹œ Refresh ํ† ํฐ์€ ์ฟ ํ‚ค, Access ํ† ํฐ์€ ํ—ค๋”๋กœ ๋„ฃ์–ด์„œ ์‘๋‹ต

 

์ด์ œ ํ”„๋ก ํŠธ๋ฅผ ๊ฐœ์„ ํ•˜๋ฉด ๋œ๋‹ค.


3. ๊ธฐ์กด (๋ณ€๊ฒฝ์ „) ๊ตฌ์กฐ

๋‚ด๊ฐ€ ๋ถ„์„ํ•œ ๊ธฐ์กด์˜ ๊ตฌ์กฐ๋ฅผ ์š”์•ฝํ•˜๋ฉด ์ด๋ ‡๋‹ค.

RefreshToken์„ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๊ณ ,

// callback.tsx
localStorage.setItem("accessToken", accessToken);
localStorage.setItem("refreshToken", refreshToken);

 

AccessToken ๋งŒ๋ฃŒ์‹œ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋˜์—ˆ๋˜ RefreshToken์„ ์ด์šฉํ•ด์„œ ์žฌ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

// utill.ts
const refreshToken = localStorage.getItem("refreshToken");
      if (!refreshToken) return Promise.reject(error);
      try {
        const response = await api.post<
          AxiosResponse<ApiResponse<RefreshTokenResponse>>
        >(ApiEndpotins.REFRESH_TOKEN, {
          refreshToken,
        });

 

๊ทธ ํ›„ ๋‹ค์‹œ ๋ฐ›์•„์˜จ ํ† ํฐ ์‘๋‹ต๋“ค์„ ๋‹ค์‹œ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์ด์—ˆ๋‹ค.

const { accessToken: newAccessToken, refreshToken: newRefreshToken } =
          response.data.data;
        localStorage.setItem("accessToken", newAccessToken);
        localStorage.setItem("refreshToken", newRefreshToken);

 

๊ทธ๋Ÿฌ๋‚˜ RefreshToken์˜ ์œ ํšจ๊ธฐ๊ฐ„์ด ์ง€๋‚˜๋„ RefreshToken์„ ๊ฐฑ์‹ ํ•  ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.

๊ณ„์† ์ฃฝ์€ ํ† ํฐ์„ ์ด์šฉํ•ด ์—‘์„ธ์Šค ํ† ํฐ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š”๊ฑฐ๋‹ค.

 

๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋‹ซ๊ฑฐ๋‚˜ ์žฅ์น˜๋ฅผ ์žฌ๋ถ€ํŒ…ํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ง€๋˜๊ธฐ์—

์บ์‹œ๋ฅผ ์ง€์šฐ์ง€ ์•Š๋Š” ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜์ง€ ์•Š์•˜๋‹ค.

 

๊ทธ๋ ‡๊ธฐ์— ๋กœ๊ทธ์•„์›ƒ๋„ ๋ถˆ๊ฐ€ํ•œ ๋ฌดํ•œ๋กœ๋”ฉ์ด ๋ฐœ์ƒํ–ˆ๋‹ค. 

 

4. ๋ณ€๊ฒฝํ•œ ์ฝ”๋“œ ๊ตฌ์กฐ

๋ฌผ๋ก  ์ด ๋ถ„๊ธฐ๋ฅผ ์žฌ์ •๋น„ํ•ด์„œ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๊ฒ ์œผ๋‚˜, 

์œ ์ €๊ฐ€ ์žˆ๋Š” ์„œ๋น„์Šค์— ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ๋‘ ํ† ํฐ์ด ๋…ธ์ถœ๋˜๋Š” ๋ฐฉ์‹์ด ๋ณด์•ˆ์ ์œผ๋กœ ๋งŒ์กฑ์Šค๋Ÿฝ์ง€ ์•Š์•˜๋‹ค.

(๊ทธ๋ž˜์„œ ์ฒ˜์Œ์—๋Š” ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ์„ธ์…˜์œผ๋กœ ์˜ฎ๊ฒจ์„œ ์•„์˜ˆ ๋ธŒ๋ผ์šฐ์ € ๋‹ซ์„๋•Œ๋งˆ๋‹ค ๋‚ ๋ฆด๊นŒ.. ํ•˜๋Š” ๋ฐฉ์‹๋„ ์ƒ๊ฐ์„ํ–ˆ๋‹ค)

๋ณด์™„์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ๋А๊ปด ์•„์˜ˆ ์ฟ ํ‚ค ๊ด€๋ฆฌ ๋ฐฉ์‹์„ ์ ์šฉํ•ด๋ณด๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

๋ฐฑ์—”๋“œ ํŒ€์›๋„ ํ”์พŒํžˆ ใ…‡ใ…‹๋ฅผ ์™ธ์ณ์ฃผ์…”์„œ ๋”์šฑ ๊ฐ์‚ฌํ–ˆ๋‹ค.

 

// utill.ts
const axiosInstance = axios.create({
  baseURL: domain,
  timeout: 8000, // ์‘๋‹ต 8์ดˆ ๋„˜์œผ๋ฉด ์˜ค๋ฅ˜
  withCredentials: true, // RefreshToken ์ฟ ํ‚ค ์ž๋™ ์ „์†ก
  headers: {
  },
});

 

์šฐ์„  ๊ธฐ๋ณธ ์‘๋‹ต ์ธ์Šคํ„ด์Šค๋ฅผ ์ˆ˜์ •ํ–ˆ๋‹ค.

withCredentials: true ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ํ–ˆ๋‹ค.

 

+) withCredentials: true๋ž€?

Axios ์š”์ฒญ์—์„œ ์ธ์ฆ ๊ด€๋ จ ์ฟ ํ‚ค, ์ž๊ฒฉ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์ „์†กํ•˜๋„๋ก ํ•˜๋Š” ์˜ต์…˜.

HttpOnly๋Š” ์„œ๋ฒ„์—์„œ ์ฟ ํ‚ค๋ฅผ๋ฐœ๊ธ‰ํ• ๋•Œ ๋”ฐ๋กœ ์„ค์ •ํ•ด์ฃผ์–ด์•ผํ•œ๋‹ค.

// ์˜ˆ์‹œ
res.cookie("refreshToken", token, {
  httpOnly: true,   // ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์ ‘๊ทผ ๋ถˆ๊ฐ€
  secure: true,     // HTTPS ํ™˜๊ฒฝ์—์„œ๋งŒ ์ „์†ก
  sameSite: "none", 
});
res.send({ success: true });

๊ทธ๋ž˜์„œ ์„œ๋ฒ„์—์„œ HttpOnly๋ฅผ ์„ค์ •ํ•ด์ฃผ๊ณ ,

ํด๋ผ์ด์–ธํŠธ์—์„œ withCredentials๋ฅผ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ์•ˆ์ „ํ•œ ์ฟ ํ‚ค ์ „์†ก์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

 

๊ทธ ํ›„, ํ—ค๋”๋กœ ๋ฐ›์€ ์•ก์„ธ์Šค ํ† ํฐ๋งŒ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

// utill.ts
    const newAccessToken = response.headers["accesstoken"];
    if (newAccessToken) {
      localStorage.setItem("accessToken", newAccessToken);
    }

 

๊ทธ๋ฆฌ๊ณ  ์•ก์„ธ์Šค ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜์—ˆ์„ ๊ฒฝ์šฐ ใ…ก

์ฟ ํ‚ค์— ์žˆ๋Š” ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์œผ๋กœ ์•ก์„ธ์Šค ํ† ํฐ์„ ์žฌ์š”์ฒญํ–ˆ๋‹ค.

 // utill.ts - AccessToken ๋งŒ๋ฃŒ์‹œ refresh ์š”์ฒญ
    if (
      errorMessage === "์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." &&
      error.config.url !== ApiEndpotins.REFRESH_TOKEN
    ) {
      try {
        const refreshRes = await axiosInstance.post(
          ApiEndpotins.REFRESH_TOKEN,
          { withCredentials: true }
        );

 

๊ทธํ›„ ์ด ์žฌ๋ฐœ๊ธ‰ ๋ฐ›์€ ์•ก์„ธ์Šค ํ† ํฐ์„ ๋‹ค์‹œ ์ €์žฅํ•˜์—ฌ

๋‹ค์‹œ ์‹คํŒจํ•œ API ์š”์ฒญ์„ ์žฌ์‹œ๋„ํ•œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ๋งŒ์•ฝ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ๋งˆ์ € ๋งŒ๋ฃŒ๋œ๋‹ค๋ฉด

 catch (err) {
        localStorage.removeItem("accessToken");
        toast.showToast(
          "error",
          "์„ธ์…˜์ด ๋งŒ๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.",
          "auth"
        );
        return Promise.reject(error);
      }

 

์•ก์„ธ์Šค ํ† ํฐ์„ ์ง€์šฐ๊ณ , ํ† ์ŠคํŠธ ๋ฉ”์„ธ์ง€๋ฅผ ๋„์šด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•œ๋‹ค.

 

+)

๊ตฌํ˜„์„ ํ•˜๋Š” ๊ณผ์ •์—์„œ ์ฐพ์•„๋ณด๋‹ˆ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ๋„ ์—ฐ์žฅํ•˜๋Š” ๊ฐœ๋…์ด ์žˆ๋Š”๋“ฏ ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•œ๊ฑด ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜๋ฉด ์ƒˆ๋กœ ์žฌ๋ฐœ๊ธ‰ํ•˜๋Š” ๋ฐฉ์‹์ด๊ธฐ์—

๊ทธ๋ƒฅ ๋งŒ๋ฃŒ์‹œ ๋‹ค์‹œ ๋กœ๊ทธ์ธ์„ ํ•จ์œผ๋กœ์จ ์žฌ๋ฐœ๊ธ‰ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ตฌํ˜„์„ํ–ˆ๋‹ค.

 

5. ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ

๊ทธ๋Ÿฐ๋ฐ ๋กœ๊ทธ์ธ์„ ํ•˜๋ฉด ๋ฐ”๋กœ ์„ธ์…˜์ด ๋งŒ๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด์„œ ๋กœ๊ทธ์ธ์ฐฝ์œผ๋กœ ๋„˜์–ด๊ฐ€๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

 

์ด์œ ๊ฐ€ ๋ญ์ธ๊ณ , ํ•˜๋‹ˆ

๋กœ๊ทธ์ธ์„ ํ•˜๊ณ  ์„ฑ๊ณตํ•  ๊ฒฝ์šฐ -> ํ† ํฐ์„ ๊ฐ๊ฐ ์ฟ ํ‚ค์™€ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๋Š”๋ฐ

๊ทธ ์‹คํ–‰ ์ž‘์—…๊ณผ

๋กœ๊ทธ์ธ ์„ฑ๊ณตํ›„ ์œ ์ € ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์š”์ฒญ์„ ๋™์‹œ์— ๋ณด๋‚ด๋‹ค๋ณด๋‹ˆ

 

์œ ์ € ์ •๋ณด์˜ ์š”์ฒญ์—์„œ ํ† ํฐ์ด ์—†์–ด์„œ ๊ฑฐ๋ถ€(!) 401 ๋‹นํ•˜๋ฉด์„œ ๋‹ค์‹œ ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ ๋Œ์•„์˜ค๋Š”๊ฒƒ์ด์—ˆ๋‹ค.

 

if (
      errorMessage === "์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค." &&
      error.config.url !== ApiEndpotins.REFRESH_TOKEN &&
      !error.config.url.includes("/auth/login") // โœ… ๋กœ๊ทธ์ธ ์š”์ฒญ์€ refresh ์‹œ๋„ ๊ธˆ์ง€
    ) {

๊ทธ๋ž˜์„œ utill.ts์— ์ด๋Ÿฌํ•œ ์ฝ”๋“œ๋ฅผ ํ•œ ์ค„ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ ,

if (isRegistered) {
     getMe();
}

์ด๋ ‡๊ฒŒ ์œ ์ € ์ •๋ณด๋ฅผ ๋ฐ”๋กœ ๋ถˆ๋Ÿฌ์˜ค๋˜ ๊ธฐ์กด์˜ ์ฝ”๋“œ๋ฅผ

// Callback.tsx
if (isRegistered) {
      setTimeout(() => {
        getMe();
      }, 150);
    }

์ด๋ ‡๊ฒŒ ์•ฝ๊ฐ„์˜ ๋Œ€๊ธฐ ํ›„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •ํ–ˆ๋‹ค.

 

๊ทธ๋ž˜์„œ ์ง€๊ธˆ์€ ์ž˜ ์ž‘๋™๋˜๋Š” ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ!^_^

์„ธ์…˜ ๋งŒ๋ฃŒ ์ž๋™ ๋กœ๊ทธ์•„์›ƒ๋„ ์ž˜ ์ž‘๋™ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ์ €์žฅ๋œ ์ฟ ํ‚ค์— ๋ณด์•ˆ ์ฒดํฌ๋„ ์ž˜ ๋œ๋‹ค.

 


๊ฐฑ์‹  ๋กœ์ง ํ๋ฆ„

1. AccessToken ๋งŒ๋ฃŒ ์‹œ
Axios ์ธํ„ฐ์…‰ํ„ฐ, 401 ์‘๋‹ต(์œ ํšจํ•˜์ง€ ์•Š์€ ํ† ํฐ์ž…๋‹ˆ๋‹ค.) ๊ฐ์ง€

 

2. /auth/refresh ์š”์ฒญ ์ „์†ก

(์ฟ ํ‚ค์— ๋‹ด๊ธด RefreshToken์ด ์„œ๋ฒ„๋กœ ์ž๋™ ์ „์†ก)

3. ์„œ๋ฒ„, RefreshToken ๊ฒ€์ฆ

์œ ํšจํ•˜๋ฉด ์ƒˆ AccessToken์„ ์‘๋‹ต ํ—ค๋”(accesstoken)๋กœ ์ „์†ก

 

4. ํ”„๋ก ํŠธ, ์ƒˆ AccessToken์„ localStorage์— ์ €์žฅ
์‹คํŒจํ–ˆ๋˜ API ์š”์ฒญ์„ ์ž๋™์œผ๋กœ ์žฌ์‹œ๋„

5. if RefreshToken์ด ๋งŒ๋ฃŒ๋œ ๊ฒฝ์šฐ

/auth/refresh ์š”์ฒญ ์ž์ฒด๊ฐ€ 401 / 403์œผ๋กœ ๊ฑฐ๋ถ€

ํ”„๋ก ํŠธ, ํ† ํฐ ์‚ญ์ œ ๋ฐ ๋กœ๊ทธ์•„์›ƒ ์ฒ˜๋ฆฌ๋กœ ์ „ํ™˜

728x90
๋ฐ˜์‘ํ˜•