LLM ์์ด์ ํธ OAuth ํ ํฐ ๋ง๋ฃ์ ์ฌ์ธ์ฆ ์ ๋ต: ์๋ํ๋ ์ํฌํ๋ก์ฐ ์์ ์ฑ ํ๋ณด
์ฝ๋ฉ์๋น ์ ๋๋ค. ์ด๋ฒ ๊ธ์ ์ ๊ฐ LLM ์์ด์ ํธ๋ฅผ ๊ฐ๋ฐํ๋ฉด์ ๊ฒช์๋ OAuth ํ ํฐ ๋ง๋ฃ ๋ฌธ์ ์ ๊ทธ ํด๊ฒฐ ๊ณผ์ ์ ๊ฒฝํ๋ ธํธ์ฒ๋ผ ์ ๋ฆฌํ ๊ฒ์ ๋๋ค. ์ธ์ ๋ชจ๋ ์๋น ๊ฐ๋ฐ์๋ค์ด ์ ์ฒ๋ผ ๋ฏธ๋ฆฌ๋ฏธ๋ฆฌ ๋ชป ์ฑ๊ฒจ์ ๋ฅ์ณ์ผ ๋ถ๋ด๋ถ๋ด ๊ฒ์ํ๋ ์ผ์ ์๊ธฐ๋ฅผ ๋ฐ๋ผ๋ฉด์ ๋ง์ด์ฃ . ์ฒ์์๋ ๊ฐ๋จํ๊ฒ Access Token๋ง ๊ฐฑ์ ํ๋ฉด ๋ ์ค ์์๋๋ฐ, Refresh Token๋ง์ ์กฐ์ฉํ ๋ง๋ฃ๋๊ฑฐ๋ ๋ฌดํจํ๋๋ ๋ฐ๋์ ์์ด์ ํธ๊ฐ ๋ฉ์ถฐ๋ฒ๋ฆฌ๋ ๊ณค๋ํ ์ํฉ์ ์ฌ๋ฌ ๋ฒ ๊ฒช์์ต๋๋ค. ๊ฒฐ๊ตญ, ๋จ์ํ ํ ํฐ์ ๊ฐฑ์ ํ๋ ๊ฒ์ ๋์ด, Refresh Token ์์ฒด์ ๋ฌดํจํ๊น์ง ๋๋นํ๋ ๊ฒฌ๊ณ ํ ์ฌ์ธ์ฆ ์ ๋ต์ด ํ์๋ผ๋ ๊ฒ์ ๊นจ๋ฌ์๋ค์. ์ด ๊ธ์ ํ๊ตญ์ด ์๋ฌธ์ ์ ๋ฆฌํ ๊ฒ์ผ๋ก, ์ฝ๋์ ์ค์ ๊ฐ์ ๊ทธ๋๋ก ์ฌํ ๊ฐ๋ฅํฉ๋๋ค.
์ด ๊ธ์์ ๋ค๋ฃจ๋ ๊ฒ
- OAuth Access Token๊ณผ Refresh Token์ ์๋ช ์ฃผ๊ธฐ ๋ฐ ๋ง๋ฃ ์๋ฆฌ
- Refresh Token๋ง์ ๋ฌดํจํ๋ ๋ ๋ฐ์ํ๋ ๋ฌธ์ ์ ๊ณผ ๊ทธ์ ๋ํ ๋๋น์ฑ
- ์๋ํ๋ ์ํฌํ๋ก์ฐ์์ OAuth ํ ํฐ์ ์์ ํ๊ฒ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ
- Refresh Token ๊ฐฑ์ ์คํจ ์, ์ฌ์ฉ์์๊ฒ ์๋์ผ๋ก ์ฌ์ธ์ฆ์ ์์ฒญํ๋ ํ๋ฆ ๊ตฌ์ถ
- ๊ตฌํ๋ ํ ํฐ ๊ด๋ฆฌ ์์คํ ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๋ ์ค์ง์ ์ธ ํ ์คํธ ๋ฐฉ๋ฒ
์ด๋ฐ ๋ถ๊ป โ LLM ์์ด์ ํธ๋ ์๋ํ๋ ์ํฌํ๋ก์ฐ๋ฅผ ๊ตฌ์ถํ๋ฉฐ ์ธ๋ถ ์๋น์ค ์ฐ๋์ OAuth๋ฅผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ยท ๋์ด๋๋ ์ค๊ธ ์ ๋
LLM ์์ด์ ํธ, ์กฐ์ฉํ ๋ฉ์ถฐ๋ฒ๋ฆฐ ์ด์ : OAuth ํ ํฐ ๋ง๋ฃ
์ ํฌ ์ง์์ ์ด์ฌํ ๋์๊ฐ๋ LLM ์์ด์ ํธ๊ฐ ์ด๋ ๋ ๊ฐ์๊ธฐ Blogger API ์ฐ๋์ ๋ฉ์ถฐ๋ฒ๋ ธ์ต๋๋ค. ํฌ์คํ ์ค์ผ์ค์ ๊น๋จน์ ๋ปํด์ ๋ง๋ค์๋๋ฐ, ์์ด์ ํธ๋ง์ ์ ์ฃผ์ธ์ ๋ฎ์ ๊น๋นกํ๋ ๊ฑด๊ฐ ์ถ์ด ๋นํฉํ๋๊ตฐ์. ์ฒ์์๋ ๋คํธ์ํฌ ๋ฌธ์ ์ธ๊ฐ ์ถ์ด ์ด๋ฆฌ์ ๋ฆฌ ํ์ธํด๋ดค์ง๋ง, ์๋ฌ ๋ก๊ทธ๋ฅผ ์์ธํ ๋ณด๋ OAuth ํ ํฐ ๋ง๋ฃ ๊ด๋ จ ๋ฉ์์ง๊ฐ ๋์ ๋์์ต๋๋ค. Access Token์ด์ผ ์๋ช ์ด ์งง์ผ๋ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ฐฑ์ ํด์ผ ํ๋ค๋ ๊ฑด ์๊ณ ์์์ฃ . ๊ทธ๋ฐ๋ฐ ๋ฌธ์ ๋ ๊ทธ๊ฒ ์๋์์ต๋๋ค. ๋จ์ํ Access Token์ด ๋ง๋ฃ๋ ๊ฒ์ด ์๋๋ผ, Access Token์ ์ฌ๋ฐ๊ธํ๋ ๋ฐ ์ฌ์ฉ๋๋ Refresh Token๋ง์ ์๋ํ์ง ์๋ ์ํฉ์ด์์ด์.
์๋ํ๋ ์์คํ ์์ ์ด๋ฐ ์ผ์ด ์๊ธฐ๋ฉด ์ ๋ง ๊ณจ์น ์ํ๋๋ค. ์ฌ๋์ด ์ง์ ๊ฐ์ ํด์ ๋ค์ ์ธ์ฆ์ ํด์ค์ผ๋ง ์์ด์ ํธ๊ฐ ๋ค์ ์์ง์ด๊ธฐ ์์ํ๊ฑฐ๋ ์. ํ๋ ๋ฒ์ด์ผ ๊ด์ฐฎ์ง๋ง, ์ด๋ฐ ์ผ์ด ๋ฐ๋ณต๋๋ค ๋ณด๋ ์ํฌํ๋ก์ฐ์ ์์ ์ฑ์ด ์ฌ๊ฐํ๊ฒ ๋จ์ด์ง๋ ๊ฒ์ ์ฒด๊ฐํ์ต๋๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ง ์๊ณ ์๋ ์ฅ๊ธฐ์ ์ผ๋ก ์๋ํ ์์คํ ์ ์ด์ํ๊ธฐ ์ด๋ ต๊ฒ ๋ค๋ ์๊ฐ์ด ๋ค์์ฃ . ๊ฒฐ๊ตญ, ์ด์ฐธ์ OAuth ํ ํฐ ๊ด๋ฆฌ ์ ๋ต์ ์ข ๋ ๊ฒฌ๊ณ ํ๊ฒ ๋ค๋ฌ์ด์ผ๊ฒ ๋ค๊ณ ๋ง์๋จน๊ฒ ๋์์ต๋๋ค.
ํนํ LLM ์์ด์ ํธ์ฒ๋ผ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์ค๋ ์๊ฐ ๋์ํ๋ ์๋น์ค์์๋ ์ด๋ฐ '์กฐ์ฉํ ์ค๋จ'์ด ๋ ์น๋ช ์ ์ ๋๋ค. ์๋ฌ๊ฐ ๋ฐ๋ก ๋์ ๋์ง ์๊ณ , ํ์ฐธ ๋ค์์ผ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค๋ ๊ฒ์ ์๊ฒ ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๊ฑฐ๋ ์. ๊ทธ๋๋ง๋ค ์๋์ผ๋ก ์ฌ์ธ์ฆ ๊ณผ์ ์ ๋ฐ๋ ๊ฒ์ ๋นํจ์จ์ ์ผ ๋ฟ๋ง ์๋๋ผ, ๊ฐ๋ฐ์์ ์์คํ ์๊ฐ๊น์ง ์ก์๋จน๋ ์ผ์ด์์ต๋๋ค. ๊ทธ๋์ Refresh Token์ ๋ง๋ฃ๋ ๋ฌดํจํ๊น์ง ๊ณ ๋ คํ ์๋ํ๋ ์ฌ์ธ์ฆ ์ ๋ต์ด ๋ฐ๋์ ํ์ํ๋ค๊ณ ํ๋จํ๊ฒ ๋์๋ค์.
Access Token์ ๋จ๋ช , Refresh Token๋ ์์ํ์ง ์๋ค
OAuth ํ ํฐ์ ๋ณด์์์ ์ด์ ๋ก ์ ํจ ๊ธฐ๊ฐ์ด ์ ํด์ ธ ์์ต๋๋ค. Access Token์ ๋ง ๊ทธ๋๋ก ํน์ ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๋ ๊ถํ์ ๋ถ์ฌํ๋ ํ ํฐ์ธ๋ฐ, ๋ณดํต ๋ช ๋ถ์์ ๋ช ์๊ฐ ์ ๋๋ก ์๋ช ์ด ๋งค์ฐ ์งง์ต๋๋ค. ๋ง์ฝ Access Token์ด ๋ฌด์ ํ์ผ๋ก ์ ํจํ๋ค๋ฉด, ํ์ทจ๋์์ ๋ ๋ณด์์ ํฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ด์ฃ . ๊ทธ๋์ Access Token์ด ๋ง๋ฃ๋๋ฉด Refresh Token์ ์ด์ฉํด ์๋ก์ด Access Token์ ๋ฐ๊ธ๋ฐ์์ผ ํฉ๋๋ค. ์ฌ๊ธฐ๊น์ง๋ ๋ง์ ๋ถ์ด ์์๋ ๋ด์ฉ์ผ ๊ฒ๋๋ค.
๋ฌธ์ ๋ Refresh Token๋ ์์ํ ์ ํจํ ๊ฒ์ด ์๋๋ผ๋ ์ ์ ๋๋ค. Refresh Token์ Access Token๋ณด๋ค๋ ํจ์ฌ ๊ธธ๊ฒ ์ ์ง๋์ง๋ง, ๊ทธ๋๋ ์๊ตฌ์ ์ด์ง๋ ์์ต๋๋ค. ์ฌ์ฉ์ ๊ถํ์ ์ฒ ํํ๊ฑฐ๋, ํน์ ๊ธฐ๊ฐ ๋์ ์ฌ์ฉํ์ง ์์์ ๋, ๋๋ ์๋น์ค ์ ๊ณต์์ ์ ์ฑ ๋ณ๊ฒฝ ๋ฑ์ผ๋ก Refresh Token์ด ๋ฌดํจํ๋ ์ ์์ต๋๋ค. ์ฌ์ง์ด Google ๊ฐ์ ๊ฒฝ์ฐ Refresh Token ๊ฐ์์ ์ ํ์ ๋๊ธฐ๋ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋๋ฌด ๋ง์ Refresh Token์ ๋ฐ๊ธ๋ฐ์ผ๋ฉด ์ค๋๋ ํ ํฐ๋ถํฐ ์๋์ผ๋ก ํ๊ธฐ๋๋ ์ ์ฑ ์ด ์์ ์ ์์ต๋๋ค. ์ด๋ฐ ์ํฉ์์๋ ๋จ์ํ Refresh Token์ผ๋ก ๊ฐฑ์ ์ ์๋ํด๋ ์คํจํ๊ฒ ๋ฉ๋๋ค.
์ ๋ ์ฒ์์๋ Refresh Token์ ํ ๋ฒ ๋ฐ์ผ๋ฉด ๋์ด๋ผ๊ณ ์์ผํ๊ฒ ์๊ฐํ์ต๋๋ค. ํ์ง๋ง ์ค์ ์ด์ ํ๊ฒฝ์์๋ ์ด๋ฐ ์์์น ๋ชปํ Refresh Token ๋ฌดํจํ ์๋๋ฆฌ์ค๊ฐ ์ข ์ข ๋ฐ์ํ๋๊ตฐ์. ์ด๋ด ๋๋ ์ด์ฉ ์ ์์ด ์ฌ์ฉ์์๊ฒ ๋ค์ ์ธ์ฆ์ ์์ฒญํ๊ณ , ์๋ก์ด Refresh Token์ ๋ฐ๊ธ๋ฐ์์ผ ํฉ๋๋ค. ์ด ๊ณผ์ ์ ์ด๋ป๊ฒ ํ๋ฉด ์๋ํ ์์คํ ์ ๋ น์ฌ๋ผ ์ ์์์ง๊ฐ ํต์ฌ ๊ณผ์ ์์ต๋๋ค.
๋จ์ Refresh Token ๊ฐฑ์ ์ผ๋ก ์ถฉ๋ถํ ์ค ์์๋๋ฐ...
์ฒ์ ๋ฌธ์ ๋ฅผ ์ธ์งํ์ ๋, ์ ๋ Access Token์ด ๋ง๋ฃ๋๋ฉด Refresh Token์ผ๋ก ๊ฐฑ์ ํ๋ ๋ก์ง๋ง ๊ตฌํํ๋ฉด ์ถฉ๋ถํ ๊ฑฐ๋ผ๊ณ ์๊ฐํ์ต๋๋ค. ํ์ด์ฌ์์๋ google-auth-oauthlib ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ์ด ๊ณผ์ ์ด ์์ฃผ ๊ฐ๋จํ๊ฒ ์ฒ๋ฆฌ๋ฉ๋๋ค. ์๋ ์ฝ๋์ฒ๋ผ credentials.refresh() ๋ฉ์๋๋ง ํธ์ถํ๋ฉด ๋๊ฑฐ๋ ์.
def refresh_oauth_token(refresh_token):
# Google OAuth ์์
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
'client_secret.json',
scopes=['https://www.googleapis.com/auth/blogger'],
redirect_uri='YOUR_REDIRECT_URI')
credentials = flow.credentials
credentials.refresh_token = refresh_token
credentials.refresh(google.auth.transport.requests.Request())
return credentials
์ด ์ฝ๋๋ ์ฃผ์ด์ง Refresh Token์ ์ด์ฉํด ์๋ก์ด Access Token์ ๋ฐ๊ธ๋ฐ๋ ๊ธฐ๋ฅ์ ์ํํฉ๋๋ค. ์ฒ์ ๋ช ๋ฒ์ ์ด ๋ฐฉ์์ผ๋ก ์ ์๋ํ๋ ๊ฒ์ ํ์ธํ๊ณ , '์, ์ด์ ๋ฌธ์ ์๊ฒ ๊ตฌ๋!' ํ๊ณ ์์ฌํ๋๊ตฐ์. ํ์ง๋ง ์์ ์ธ๊ธํ๋ฏ์ด, Refresh Token ์์ฒด์ ์ ํจ ๊ธฐ๊ฐ์ด ๋ง๋ฃ๋๊ฑฐ๋ ์ด๋ค ์ด์ ๋ก๋ ๋ฌดํจํ๋๋ ์ํฉ์ด ๋ฐ์ํ์, ์ด refresh() ๋ฉ์๋ ํธ์ถ ์์ฒด๊ฐ ์คํจํ๋ ๋ฌธ์ ๊ฐ ๋ค์ ๋ถ๊ฑฐ์ก์ต๋๋ค. ์ด ๊ฒฝ์ฐ์๋ google.auth.exceptions.RefreshError ๊ฐ์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉฐ ์์คํ
์ด ๋ฉ์ถฐ๋ฒ๋ ธ์ต๋๋ค.
๋จ์ํ Access Token ๊ฐฑ์ ์๋ง ์ด์ ์ ๋ง์ถ๋ค ๋ณด๋, Refresh Token ์์ฒด์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ๊ณผํ ๊ฒ์ด์ฃ . ๊ฒฐ๊ตญ, ์ด ์์ธ๋ฅผ ์ฒ๋ฆฌํ๊ณ ๋ค์ ์คํ ์ผ๋ก ๋์ด๊ฐ ์ ์๋ ๋ ๊ฒฌ๊ณ ํ ๋ก์ง์ด ํ์ํ๋ค๋ ๊ฒ์ ๊นจ๋ซ๊ฒ ๋์์ต๋๋ค. ๋จ์ํ ์ค๋ฅ๋ฅผ ๋ฑ์ด๋ด๊ณ ๋ฉ์ถ๋ ๊ฒ์ด ์๋๋ผ, ์ค๋ฅ ๋ฐ์ ์ ์๋์ผ๋ก ๋ณต๊ตฌ ์๋๋ฆฌ์ค๋ฅผ ๊ฐ๋ํด์ผ๋ง ์ง์ ํ ์๋ํ ์์คํ ์ด๋ผ๊ณ ํ ์ ์๊ฒ ๋๊ตฐ์.
Refresh Token ๋ฌดํจํ ์๋๋ฆฌ์ค, ์๋ ์ฌ์ธ์ฆ ํ๋ฆ ๋ง๋ค๊ธฐ
Refresh Token ๊ฐฑ์ ๋ง์ ์คํจํ๋ ์ํฉ์ ๋๋นํ๊ธฐ ์ํด, ์ ๋ ์์ธ ์ฒ๋ฆฌ ๋ก์ง์ ๊ฐํํ๊ณ ์๋ ์ฌ์ธ์ฆ ํ๋ฆ์ ๊ตฌ์ถํ์ต๋๋ค. ํต์ฌ์ google.auth.exceptions.RefreshError๋ฅผ ์ก์๋ด๋ ๊ฒ์
๋๋ค. ์ด ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ํ์ฌ ๊ฐ์ง๊ณ ์๋ Refresh Token์ ๋ ์ด์ ์ ํจํ์ง ์๋ค๋ ๋ป์ด๋ฏ๋ก, ํด๋น ํ ํฐ ์ ๋ณด๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฆ์ ํ๊ธฐํด์ผ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์์๊ฒ ์๋ก์ด ์ธ์ฆ์ ์์ฒญํด์ผ ํ์ฃ .
try:
# API ํธ์ถ ์๋
response = service.api_call()
except google.auth.exceptions.RefreshError as e:
# Refresh Token ๋ง๋ฃ ๋๋ ๋ฌดํจํ
print(f"Refresh Token ์ค๋ฅ ๋ฐ์: {e}. ํ ํฐ์ ํ๊ธฐํ๊ณ ์ฌ์ธ์ฆ์ด ํ์ํฉ๋๋ค.")
delete_invalid_token_from_db(user_id)
auth_url = generate_new_authorization_url(scopes)
send_reauthentication_request(user_id, auth_url)
์ ์ฝ๋๋ฅผ ๋ณด๋ฉด, RefreshError ๋ฐ์ ์ delete_invalid_token_from_db ํจ์๋ฅผ ํธ์ถํด ๋ฌดํจํ๋ ํ ํฐ์ ์ ์ฅ์์์ ์ง์๋ฒ๋ฆฝ๋๋ค. ๊ทธ๋ฆฌ๊ณ generate_new_authorization_url ํจ์๋ฅผ ํตํด ์๋ก์ด ์ธ์ฆ URL์ ์์ฑํฉ๋๋ค. ์ด URL์ ์ฌ์ฉ์๊ฐ ๋ค์ Google์ ๋ก๊ทธ์ธํ์ฌ ๊ถํ์ ๋ถ์ฌํ๋๋ก ์ ๋ํ๋ ์ญํ ์ ํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก send_reauthentication_request ํจ์๋ฅผ ํธ์ถํ์ฌ ์ฌ์ฉ์์๊ฒ ์ด ์ฌ์ธ์ฆ URL์ ์ด๋ค ๋ฐฉ์์ผ๋ก๋ (์ด๋ฉ์ผ, ์๋ฆผ ๋ฑ) ์ ๋ฌํ๊ฒ ๋ฉ๋๋ค. ์ด ๊ณผ์ ์ ํตํด ์๋ ๊ฐ์
์ ์ต์ํํ๊ณ , ์์คํ
์ด ์ค์ค๋ก ๋ณต๊ตฌ ๊ณผ์ ์ ์์ํ ์ ์๋๋ก ๋ง๋ค์์ต๋๋ค.
์ด๋ฐ ํ๋ฆ์ ํตํด ์์ด์ ํธ์ ์๋ ์ค๋จ ์๊ฐ์ ์ต์ํํ๊ณ , ๊ฐ๋ฐ์๊ฐ ์ผ์ผ์ด ํ ํฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฌ ๊ฐ๋ ์๊ณ ๋ฅผ ๋ ์ ์๊ฒ ๋ฉ๋๋ค. ์ค์ํ ๊ฒ์ ์ฌ์ฉ์์๊ฒ '์' ์ฌ์ธ์ฆ์ด ํ์ํ์ง, '์ด๋ป๊ฒ' ํด์ผ ํ๋์ง ๋ช ํํ๊ฒ ์๋ดํ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋์ผ ์ฌ์ฉ์๊ฐ ํผ๋ ์์ด ์ฌ์ธ์ฆ ์ ์ฐจ๋ฅผ ์๋ฃํ๊ณ , ์์ด์ ํธ๊ฐ ๋ค์ ์ ์ ์๋ํ ์ ์์ต๋๋ค.
.ba-pc{display:none}.ba-mo{display:block}@media (min-width:768px){.ba-pc{display:block}.ba-mo{display:none}}
ํ ํฐ์ ๋ฌผ๋ก , ์ฌ์ธ์ฆ์ ์ํ ์ ๋ณด๊น์ง ๊ผผ๊ผผํ ์ ์ฅํ๊ธฐ
์๋ํ๋ ์ฌ์ธ์ฆ ํ๋ฆ์ ๊ตฌํํ๋ ค๋ฉด, ๋จ์ํ Access Token๊ณผ Refresh Token๋ง ์ ์ฅํด์๋ ์ ๋ฉ๋๋ค. ํ ํฐ์ ๊ฐฑ์ ํ๊ฑฐ๋ ์ฌ์ธ์ฆ URL์ ์์ฑํ ๋ ํ์ํ ๋ถ๊ฐ ์ ๋ณด๋ค๋ ํจ๊ป ์ ์ฅํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ด๋ค scope๋ก ์ธ์ฆ์ ๋ฐ์๋์ง, ์ด๋ค client_id์ client_secret์ ์ฌ์ฉํ๋์ง ๊ฐ์ ์ ๋ณด๋ค ๋ง์ด์ฃ . ์ ๋ ์ด๋ฐ ์ ๋ณด๋ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ์ ํจ๊ป ์ ์ฅํ๋ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ์ต๋๋ค. ์๋๋ ์ ๊ฐ ์ฌ์ฉํ oauth_tokens ํ
์ด๋ธ์ ์คํค๋ง ์์์
๋๋ค.
CREATE TABLE oauth_tokens (
user_id VARCHAR(255) PRIMARY KEY,
access_token TEXT NOT NULL,
refresh_token TEXT NOT NULL,
token_uri TEXT NOT NULL,
client_id TEXT NOT NULL,
client_secret TEXT NOT NULL,
scopes TEXT NOT NULL,
expires_at DATETIME NOT NULL
);
์ฌ๊ธฐ์ user_id๋ ์ด๋ค ์ฌ์ฉ์์ ํ ํฐ์ธ์ง ์๋ณํ๊ธฐ ์ํ ๊ฐ์ด๊ณ , access_token๊ณผ refresh_token์ ๋น์ฐํ ํ์์
๋๋ค. token_uri, client_id, client_secret์ Google OAuth ํ๋ฆ์์ ํ ํฐ์ ๊ฐฑ์ ํ๊ฑฐ๋ ์ฌ์ธ์ฆ URL์ ๋ง๋ค ๋ ํ์ํ ์ ๋ณด๋ค์ด๊ณ ์. ํนํ scopes ํ๋๋ ์์ฃผ ์ค์ํ๋ฐ์, ์ฌ์ฉ์๊ฐ ์ฒ์ ์ธ์ฆํ ๋ ์ด๋ค ๊ถํ(์: Blogger API ์ฐ๊ธฐ ๊ถํ)์ ๋ถ์ฌํ๋์ง ๊ธฐ๋กํด๋์ด์ผ ๋์ค์ ์ฌ์ธ์ฆ์ ์์ฒญํ ๋ ๋์ผํ ๊ถํ์ ๋ค์ ์์ฒญํ ์ ์์ต๋๋ค. ๋ง์ฝ ์ด ์ ๋ณด๋ฅผ ์์ด๋ฒ๋ฆฌ๋ฉด, ์ฌ์ธ์ฆ ์ ํ์ํ ๊ถํ์ ์ ํํ ์์ฒญํ์ง ๋ชปํด์ ๋ ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
expires_at ํ๋๋ Access Token์ ๋ง๋ฃ ์๊ฐ์ ๊ธฐ๋กํ๋ ์ฉ๋์
๋๋ค. ์ด ์ ๋ณด๋ฅผ ์ด์ฉํ๋ฉด Access Token์ด ๋ง๋ฃ๋๊ธฐ ์ ์ ๋ฏธ๋ฆฌ ๊ฐฑ์ ์ ์๋ํ๋ ์ ์ ์ ์ธ ์ ๋ต์ ์ธ์ธ ์๋ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ์ํ ๋ชจ๋ ์ ๋ณด๋ฅผ ํ๊ณณ์ ๋ชจ์๋๋ฉด, ํ ํฐ ๊ด๋ฆฌ ๋ก์ง์ด ํจ์ฌ ๊ฐ๊ฒฐํด์ง๊ณ ์์ ์ ์ผ๋ก ์ด์๋ ์ ์์ต๋๋ค.
์ ๋ง ์ ์๋ํ ๊น? ๋ง๋ฃ ๋ฐ ๋ฌดํจํ ์๋๋ฆฌ์ค ๊ฒ์ฆ
์๋ฌด๋ฆฌ ์ข์ ๋ก์ง์ ๋ง๋ค์์ด๋ ์ค์ ๋ก ์ ์๋ํ๋์ง ํ์ธํ๋ ๊ณผ์ ์ ํ์์
๋๋ค. ์ ๋ ๋ ๊ฐ์ง ์ฃผ์ ์๋๋ฆฌ์ค๋ฅผ ํ
์คํธํ์ต๋๋ค. ์ฒซ ๋ฒ์งธ๋ Access Token ๋ง๋ฃ ํ Refresh Token์ผ๋ก ์ ์์ ์ผ๋ก ๊ฐฑ์ ๋๋์ง ํ์ธํ๋ ๊ฒ์ด์์ต๋๋ค. Access Token์ ์ ํจ ๊ธฐ๊ฐ์ ์ผ๋ถ๋ฌ ์งง๊ฒ ์ค์ ํ๊ฑฐ๋, Access Token์ ์๋์ผ๋ก ์ญ์ ํ ๋ค ๋ค์ API ํธ์ถ ์ ์๋์ผ๋ก ์ Access Token์ด ๋ฐ๊ธ๋๋์ง ๋ก๊ทธ๋ฅผ ํตํด ํ์ธํ์ต๋๋ค. ์ด๋, API ํธ์ถ ์ ์ credentials.valid ์์ฑ์ ์ฒดํฌํ์ฌ False๋ผ๋ฉด credentials.refresh()๊ฐ ํธ์ถ๋๋์ง ์ดํด๋ณด๋ฉด ๋ฉ๋๋ค.
๋ ๋ฒ์งธ์ด์ ๋ ์ค์ํ ํ
์คํธ๋ Refresh Token์ด ๋ฌดํจํ๋์์ ๋ ์์คํ
์ด ์ ๋๋ก ๋์ํ๋์ง ํ์ธํ๋ ๊ฒ์ด์์ต๋๋ค. ์ด๋ฅผ ์ํด ์ ๋ Google ๊ณ์ ์ค์ ์ ๋ค์ด๊ฐ์ ์ง์ ํด๋น ์ ํ๋ฆฌ์ผ์ด์
์ ๊ถํ์ ์ฒ ํํ๊ฑฐ๋, ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ Refresh Token์ ๊ฐ์ ๋ก ์๋ชป๋ ๊ฐ์ผ๋ก ๋ณ๊ฒฝํ์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ API ํธ์ถ์ ์๋ํ์ ๋, ์์คํ
์ด google.auth.exceptions.RefreshError๋ฅผ ์ ํํ ์ก์๋ด๋์ง ํ์ธํ์ต๋๋ค. ๋ก๊ทธ์ 'Refresh Token ์ค๋ฅ ๋ฐ์' ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋๊ณ , ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํด๋น ํ ํฐ ์ ๋ณด๊ฐ ์ญ์ ๋๋์ง, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์์๊ฒ ์ฌ์ธ์ฆ URL์ด ํฌํจ๋ ์๋ฆผ์ด ์ ๋๋ก ๋ฐ์ก๋๋์ง ๋ฉด๋ฐํ ์ง์ผ๋ดค์ต๋๋ค.
์ฌ์ธ์ฆ URL์ ํตํด ๋ค์ ์ธ์ฆ ๊ณผ์ ์ ๊ฑฐ์น ํ, LLM ์์ด์ ํธ๊ฐ ์ ์์ ์ผ๋ก Blogger API์ ์ฐ๋๋์ด ํฌ์คํ ์ ๋ฐํํ๋ ๊ฒ๊น์ง ํ์ธํด์ผ ๋น๋ก์ ์์ฌํ ์ ์์์ต๋๋ค. ์ด ๊ณผ์ ์ ํตํด ์ ๊ฐ ๊ตฌ์ถํ ํ ํฐ ๊ด๋ฆฌ ์์คํ ์ด ๋จ์ํ Access Token ๊ฐฑ์ ์ ๋์ด, Refresh Token์ ๋ฌดํจํ๋ผ๋ ์์ธ ์ํฉ๊น์ง ๊ฒฌ๊ณ ํ๊ฒ ์ฒ๋ฆฌํ๋ค๋ ๊ฒ์ ์ ์ฆํ ์ ์์๋ค์.
๋ง๋ฌด๋ฆฌ
LLM ์์ด์ ํธ๋ ์๋ํ๋ ์์คํ ์ ์ด์ํ๋ฉด์ OAuth ํ ํฐ ๊ด๋ฆฌ๋ ๋จ์ํ Access Token์ ๊ฐฑ์ ํ๋ ๊ฒ์ ๋์ด, Refresh Token์ ๋ง๋ฃ๋ ๋ฌดํจํ๊น์ง ๊ณ ๋ คํด์ผ ํ๋ ๋ณต์กํ ๋ฌธ์ ์ ๋๋ค. ์ด๋ฒ์ ๊ฒช์ ๊ฒฝํ์ ํตํด ์์ธ ์ํฉ๊น์ง ๋๋นํ๋ ๊ฒฌ๊ณ ํ ์ฌ์ธ์ฆ ์ ๋ต์ด ์ํฌํ๋ก์ฐ์ ์์ ์ฑ๊ณผ ์ด์ ํจ์จ์ฑ์ ํฌ๊ฒ ๋์ฌ์ค๋ค๋ ๊ฒ์ ๊นจ๋ฌ์์ต๋๋ค. ๊ฒฐ๊ตญ, '์ค๋ง' ํ๋ ๋ง์์ผ๋ก ๊ฐ๊ณผํ๋ ๋ถ๋ถ์ด ์์คํ ์ ์ฒด๋ฅผ ๋ฉ์ถ๊ฒ ํ ์ ์๋ค๋ ๊ฒ์ ๋ค์ ํ๋ฒ ๋ฐฐ์ฐ๊ฒ ๋์๋ค์. ๋ค์๋ฒ์๋ ๋ฏธ๋ฆฌ๋ฏธ๋ฆฌ ์ ์ฑ๊ฒจ์ ์ด๋ฐ ์ํ์ฐฉ์ค๋ฅผ ์ค์ฌ๋๊ฐ์ผ๊ฒ ์ต๋๋ค. If the result differs, check the version first โ that is the usual cause.












