devlog study backend nextauth oauth2 server jwt
Auth.js ๐
- Auth.js - Docs
- LLM ํ์ฉ ๋ด์ฉ ๋ณด์ถฉ
์๋ฌธ๊ฐ๊ธฐ
์ธ์
๋ง๋ฃ ์๊ฐ์ ์ฐ์ฅํ๋ ค๋ฉด access_token์ ๋งค๋ฒ ์๋ก ๋ฐ๊ธ?
๋ฌธ์ :
- ๋ก๊ทธ์ธ์ํ๋ก ์ธ์ ๋ง๋ฃ ์๊ฐ์ ์ด๊ณผํ๋ฉด jwt ํ ํฐ ๊ด๋ จ ์๋ฌ๊ฐ ๋ฐ์
// middleware.ts
if (!token) {
// ์ฌ๊ธฐ๋ก ๋น ์ง โ ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๊ฐ์ ์ด๋
return NextResponse.redirect(
new URL(`/sign?redirectTo=${pathname}`, req.url)
);
}- ๋งค ์์ฒญ๋ง๋ค
access_token์ ๋ฐ๊ธํ๋ฉด:- ๋ถํ์ํ ์๋ฒ ์์ ์ ํ๊ฒ๋จ
ํด๊ฒฐ :
middleware์์ ์ธ์ ๋ง๋ฃ์๊ฐ์ ์ฒดํฌ &
REFRESH_THRESHHOLD์ ๋ง์ถฐ ์ฟ ํค๋ฅผ ์๋ก ๊ตฌ์
๐ 1. auth.ts - NextAuth ์ค์
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
Google({
authorization: {
params: {
prompt: "consent",
access_type: "offline", // ๐ ์ค์!
response_type: "code",
},
},
}),
],
});access_type: "offline"์ญํ- Google OAuth์์ Refresh Token์ ๋ฐ๊ธฐ ์ํ ์ค์
- ์ด๊ฒ ์์ผ๋ฉด access_token๋ง ๋ฐ์์์ ์ธ์ ๋ง๋ฃ์ ์ฌ๋ก๊ทธ์ธ ํ์
offline์ผ๋ก ์ค์ ํ๋ฉด ํ ํฐ ๊ฐฑ์ ๊ฐ๋ฅ
๐ก๏ธ 2. middleware.ts - ํต์ฌ ๋ก์ง
- ๊ธฐ์กด token ์ ๋ณด๋ฅผ ์ฌ์ธ์ฝ๋ฉํด์ ๋ง๋ฃ ์๊ฐ์ ์ฐ์ฅ
encode()ํจ์๊ฐ ์๋ก์ด jwt๋ฅผ ์์ฑ- ์ด๊ฑธ ์ฟ ํค๋ก ๋ค์ ๊ตฌ์์ ๋ธ๋ผ์ฐ์ ์ ์ ๋ฌ
- ํ ํฐ ๊ฐ์ ธ์ค๊ธฐ โ ๋ก๊ทธ์ธ ์ฒดํฌ โ ๋ง๋ฃ ์๊ฐ ์ฒดํฌ
const token = await getToken({ req, secret: SECRET });
if (!token && NEED_COOKIES.includes(pathname))
return NextResponse.next();
if (!token)
return NextResponse.redirect(
new URL(`/sign?redirectTo=${pathname}`, req.url)
);
const REFRESH_THRESHOLD = 10 * 60 * 1000; // 10๋ถ
const exp = token.exp ? token.exp * 1000 : 0;
// ๋ง๋ฃ ์๋ฐ : 10๋ถ ์ด๋ด๋ก ์ ๊ทผํ์ ๊ฒฝ์ฐ์๋ง ๊ฐฑ์ โ ์ฟ ํค ์๋ก ๊ตฌ์
if (exp - Date.now() < MAX_AGE * 1000 - REFRESH_THRESHOLD) {
const newToken = await encode({ ... });
res.cookies.set({ ... });
}- ์ฟ ํค ์๋ก ๊ตฝ๊ธฐ
const res = NextResponse.next();
const newToken = await encode({
token, // ๊ธฐ์กด ํ ํฐ ์ ๋ณด ์ ์ง
secret: SECRET,
salt: SALT,
maxAge: MAX_AGE, // ๋ง๋ฃ ์๊ฐ ์ฌ์ค์
});
// ์ฟ ํค๊ตฝ๊ธฐ
res.cookies.set({
name: SALT,
value: newToken, // new encoded token
maxAge: MAX_AGE, // 'undefined'๋ฉด ๋ธ๋ผ์ฐ์ ๋ซ์๋๊น์ง ์ ์ง - e.g. ์ฃผ์ฐจ๋น ์ ์ฐ์ฑ
httpOnly: true, // XSS๋ฐฉ์ด - JavaScript๋ก ์ ๊ทผ ๋ถ๊ฐ
secure: process.env.NODE_ENV === "production", // HTTPS๋ง
sameSite: "lax", // CSRF ๋ฐฉ์ด
path: "/",
});๐ ์ค์ ๋์ ํ์๋ผ์ธ
1์ 1์ผ 00:00 - ๋ก๊ทธ์ธ
โโ ์ฟ ํค ์์ฑ: ๋ง๋ฃ 1์ 31์ผ 00:00
โ
1์ 5์ผ 10:00 - ํ์ด์ง ์ ์
โโ Middleware ์คํ
โโ ๋จ์ ์๊ฐ: 25์ผ 14์๊ฐ
โโ ์กฐ๊ฑด ์ฒดํฌ: 25์ผ < (30์ผ - 10๋ถ)? YES
โโ โ
์ฟ ํค ์๋ก ๊ตฌ์
โโ ์ ๋ง๋ฃ: 2์ 4์ผ 10:00
โ
1์ 10์ผ 15:00 - ๋ ์ ์
โโ Middleware ์คํ
โโ ๋จ์ ์๊ฐ: 24์ผ 19์๊ฐ
โโ โ
์ฟ ํค ์๋ก ๊ตฌ์
โโ ์ ๋ง๋ฃ: 2์ 9์ผ 15:00๋ด์ด๋ณด๊ธฐ
OAuth2
- ๋ค๋ฅธ ์๋น์ค ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ ํ์ฉํ๋ ํ์ค ํ๋กํ ์ฝ

Client : Next.js app / resource Owner : User / Authorization Server : Google server / Resource Server : Google API
๊ธฐ๋ณธ ํ๋ฆ
| RFC ๋จ๊ณ | ์ค์ ๋จ๊ณ |
|---|---|
| (A) Authorization Request | โ ๋ก๊ทธ์ธ ๋ฒํผ โ Provider๋ก ์ด๋(๊ถํ ์์ฒญ ์์) |
| (B) Authorization Grant | โก ์ฌ์ฉ์๊ฐ ๋์ โ ๊ถํ ๋ถ์ฌ ์ฌ์ค ํ์ |
| (C) Authorization Grant โ Auth Server | โข ํด๋ผ์ด์ธํธ๊ฐ ๊ทธ โ๊ถํโ(=์ฝ๋)์ ์๋ฒ๋ก ์ ์ถ(์ฝ๋ ๊ตํ) |
| (D) Access Token | โฃ ์๋ฒ๊ฐ ์ฝ๋๋ฅผ ๊ฒ์ฆํ๊ณ ์ก์ธ์ค ํ ํฐ ๋ฐ๊ธ |
| (E) Access Token โ Resource Server | โค ์ก์ธ์ค ํ ํฐ์ผ๋ก API ์์ฒญ |
| (F) Protected Resource | โฅ ๋ณดํธ ์์(ํ๋กํ ๋ฑ) ์๋ต : ์ธ์ /JWT ์์ฑ โ ์ฟ ํค(HttpOnly)์ ์ ์ฅ |
- ๋ด ์ฑ์ด ์ง์ ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ฐ์ง ์๊ณ , ํ ํฐ์ ํตํด ๊ฐ์ ์ ์ผ๋ก ๋ก๊ทธ์ธ ์ํ๋ฅผ ํ์ธ
Access Token / Refresh Token
- Access Token
- ์ ํจ๊ธฐ๊ฐ์ด ์งง์ (์: 1์๊ฐ)
- API ์์ฒญํ ๋
๋๋ ์ธ์ฆ๋ ์ฌ์ฉ์๋ผ๊ณ ์ฆ๋ช ํ๋ ์ฉ๋
- Refresh Token
- Access Token ๋ง๋ฃ๋์๋ ์๋ก ๋ฐ๊ธ๋ฐ๋๋ฐ ์ฌ์ฉ
- ์๋ฒ์์ ์์ ํ๊ฒ ๊ด๋ฆฌํด์ผ ํจ
OAuth2 Provider์์ Access Token์ผ๋ก ๋ฐ์์จ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ์
Auth.js ๊ธฐ์ค
์ธ์ DB ๋ฐฉ์
- ์๋ฒ๊ฐ DB์ โ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ํโ๋ฅผ ์ ์ฅํด๋
- ๋ธ๋ผ์ฐ์ ์์ ์ธ์ ID๋ฅผ ์ฟ ํค๋ก ๋ด๋ ค์ค
- ๋ค์ ์์ฒญ์์ ์ฟ ๋ฆฌ๋ฅผ ๋ณด๊ณ DB์์ ํด๋น ์ ์ ์ ๋ณด๋ฅผ ์ฐพ์์ด
JWT ๋ฐฉ์(Auth.js ๊ธฐ๋ณธ)
- ์๋ฒ๊ฐ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก
JWT(Json Web Token)์ ๋ฐ๊ธ - JWT๋ โ์ด ์ ์ ๋ ๋๊ตฌ๋คโ ๋ผ๋ ์ ๋ณด๋ฅผ ์ํธํ๋ ์๋ช ์ผ๋ก ๋ณด์ฆ
- ๋ธ๋ผ์ฐ์ ์ฟ ํค์ JWT๋ฅผ ๋ฃ์ด์ค
- ๋ค์ ์์ฒญ์์ ์๋ฒ๋ JWT๋ง ๊ฒ์ฆ โ DB ์กฐํ ๋ถํ์
- Access Token = Provider(๊ตฌ๊ธ/๊นํ๋ธ)์ ํต์ ์ฉ
- JWT/์ธ์ = ์ฐ๋ฆฌ ์ฑ ๋ด๋ถ์์ ์ฌ์ฉ์ ์ธ์ฆ์ ๊ด๋ฆฌํ๊ธฐ ์ํ ๋๊ตฌ
๋ธ๋ผ์ฐ์ ์ ๋ฐ์ดํฐ ์ ์ฅํ๋ ๋ฐฉ๋ฒ
- ์ฟ ํค(HttpOnly) : ๋ณด์์ ์์ , ์๋์ผ๋ก ์์ฒญ์ ๋ถ์(Auth.js ๊ธฐ๋ณธ)
- Local storage : ์ง์ JS๋ก ์ ๊ทผํด์ผํ๊ณ ํดํน(XSS)์ ์ทจ์ฝ โ ์์ฆ์ ์์
NextAuth.js
- ์๋ฒ์์ ์ธ์ ์ ์ฟ ํค ๊ธฐ๋ฐ์ผ๋ก ๊ด๋ฆฌ
- ํด๋ผ์ด์ธํธ์์ ์ด ์ธ์ ์ ์ฝ์ด ๋ก๊ทธ์ธ/๋ก๊ทธ์์ ์ํ๋ฅผ ์์ ์๊ฒ ํจ