{"componentChunkName":"component---src-templates-blog-post-js","path":"/etc/OAuth-2.0과-JWT-완전정복-인증-인가-실전-가이드/","result":{"data":{"site":{"siteMetadata":{"title":"Bottlehs Tech Blog","description":"웹·앱·AI 개발자 전병훈(bottlehs)의 기술 블로그. AI·LLM, JavaScript·Vue, Spring Boot, 알고리즘, 블록체인 실무 가이드를 다룹니다","siteUrl":"https://www.bottlehs.dev","author":{"name":"Jeon Byung Hun","summary":"개발을 즐기는 bottlehs - Engineer, MS, AI, FE, BE, OS, IOT, Blockchain, 설계, 테스트"},"social":{"github":"bottlehs","codepen":"bottlehs"}}},"markdownRemark":{"id":"75229308-eba3-5e31-b8f6-eeee0f49880b","excerpt":"OAuth 2.0과 JWT 완전정복 - 인증/인가 실전 가이드 OAuth 2.0과 JWT는 현대적인 웹 애플리케이션의 인증/인가 시스템의 핵심이다. 이 글은 OAuth 2.0의 다양한 플로우와 JWT의 생성/검증을 실전 예제와 함께 정리한다. 1. OAuth 2.0 기초 1-…","html":"<h1 id=\"oauth-20과-jwt-완전정복---인증인가-실전-가이드\" style=\"position:relative;\"><a href=\"#oauth-20%EA%B3%BC-jwt-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5---%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C\" aria-label=\"oauth 20과 jwt 완전정복   인증인가 실전 가이드 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>OAuth 2.0과 JWT 완전정복 - 인증/인가 실전 가이드</h1>\n<p>OAuth 2.0과 JWT는 현대적인 웹 애플리케이션의 인증/인가 시스템의 핵심이다. 이 글은 OAuth 2.0의 다양한 플로우와 JWT의 생성/검증을 실전 예제와 함께 정리한다.</p>\n<h2 id=\"1-oauth-20-기초\" style=\"position:relative;\"><a href=\"#1-oauth-20-%EA%B8%B0%EC%B4%88\" aria-label=\"1 oauth 20 기초 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. OAuth 2.0 기초</h2>\n<h3 id=\"1-1-oauth-20-개요\" style=\"position:relative;\"><a href=\"#1-1-oauth-20-%EA%B0%9C%EC%9A%94\" aria-label=\"1 1 oauth 20 개요 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-1. OAuth 2.0 개요</h3>\n<p>OAuth 2.0은 제3자 애플리케이션에게 제한된 리소스 접근 권한을 부여하는 인가 프레임워크다.</p>\n<p><strong>주요 역할:</strong></p>\n<ul>\n<li><strong>Resource Owner</strong>: 리소스 소유자 (사용자)</li>\n<li><strong>Client</strong>: 리소스에 접근하려는 애플리케이션</li>\n<li><strong>Authorization Server</strong>: 액세스 토큰 발급</li>\n<li><strong>Resource Server</strong>: 보호된 리소스 제공</li>\n</ul>\n<h3 id=\"1-2-oauth-20-플로우-종류\" style=\"position:relative;\"><a href=\"#1-2-oauth-20-%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%A2%85%EB%A5%98\" aria-label=\"1 2 oauth 20 플로우 종류 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-2. OAuth 2.0 플로우 종류</h3>\n<ol>\n<li><strong>Authorization Code Flow</strong>: 가장 안전한 플로우</li>\n<li><strong>Implicit Flow</strong>: 단순하지만 보안 취약 (deprecated)</li>\n<li><strong>Client Credentials Flow</strong>: 서버 간 통신</li>\n<li><strong>Resource Owner Password Credentials Flow</strong>: 신뢰할 수 있는 클라이언트용</li>\n<li><strong>Device Flow</strong>: IoT 디바이스용</li>\n</ol>\n<h2 id=\"2-authorization-code-flow\" style=\"position:relative;\"><a href=\"#2-authorization-code-flow\" aria-label=\"2 authorization code flow permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. Authorization Code Flow</h2>\n<h3 id=\"2-1-기본-플로우\" style=\"position:relative;\"><a href=\"#2-1-%EA%B8%B0%EB%B3%B8-%ED%94%8C%EB%A1%9C%EC%9A%B0\" aria-label=\"2 1 기본 플로우 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-1. 기본 플로우</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> flask <span class=\"token keyword\">import</span> Flask<span class=\"token punctuation\">,</span> redirect<span class=\"token punctuation\">,</span> request<span class=\"token punctuation\">,</span> session\n<span class=\"token keyword\">import</span> requests\n<span class=\"token keyword\">import</span> secrets\n\napp <span class=\"token operator\">=</span> Flask<span class=\"token punctuation\">(</span>__name__<span class=\"token punctuation\">)</span>\napp<span class=\"token punctuation\">.</span>secret_key <span class=\"token operator\">=</span> secrets<span class=\"token punctuation\">.</span>token_hex<span class=\"token punctuation\">(</span><span class=\"token number\">16</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># OAuth 2.0 설정</span>\nCLIENT_ID <span class=\"token operator\">=</span> <span class=\"token string\">\"your-client-id\"</span>\nCLIENT_SECRET <span class=\"token operator\">=</span> <span class=\"token string\">\"your-client-secret\"</span>\nREDIRECT_URI <span class=\"token operator\">=</span> <span class=\"token string\">\"http://localhost:5000/callback\"</span>\nAUTHORIZATION_URL <span class=\"token operator\">=</span> <span class=\"token string\">\"https://oauth-provider.com/authorize\"</span>\nTOKEN_URL <span class=\"token operator\">=</span> <span class=\"token string\">\"https://oauth-provider.com/token\"</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/login\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">login</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token comment\"># 1. Authorization Code 요청</span>\n    state <span class=\"token operator\">=</span> secrets<span class=\"token punctuation\">.</span>token_urlsafe<span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span>\n    session<span class=\"token punctuation\">[</span><span class=\"token string\">'oauth_state'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> state\n    \n    params <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"response_type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"code\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">:</span> CLIENT_ID<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"redirect_uri\"</span><span class=\"token punctuation\">:</span> REDIRECT_URI<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"read write\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"state\"</span><span class=\"token punctuation\">:</span> state\n    <span class=\"token punctuation\">}</span>\n    \n    auth_url <span class=\"token operator\">=</span> <span class=\"token string-interpolation\"><span class=\"token string\">f\"</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>AUTHORIZATION_URL<span class=\"token punctuation\">}</span></span><span class=\"token string\">?</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>requests<span class=\"token punctuation\">.</span>compat<span class=\"token punctuation\">.</span>urlencode<span class=\"token punctuation\">(</span>params<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span>\n    <span class=\"token keyword\">return</span> redirect<span class=\"token punctuation\">(</span>auth_url<span class=\"token punctuation\">)</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/callback\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">callback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token comment\"># 2. Authorization Code 수신</span>\n    code <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"code\"</span><span class=\"token punctuation\">)</span>\n    state <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"state\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token comment\"># State 검증 (CSRF 방지)</span>\n    <span class=\"token keyword\">if</span> state <span class=\"token operator\">!=</span> session<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'oauth_state'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token string\">\"Invalid state parameter\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n    \n    <span class=\"token comment\"># 3. Access Token 교환</span>\n    token_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"grant_type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"authorization_code\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"code\"</span><span class=\"token punctuation\">:</span> code<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"redirect_uri\"</span><span class=\"token punctuation\">:</span> REDIRECT_URI<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">:</span> CLIENT_ID<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"client_secret\"</span><span class=\"token punctuation\">:</span> CLIENT_SECRET\n    <span class=\"token punctuation\">}</span>\n    \n    response <span class=\"token operator\">=</span> requests<span class=\"token punctuation\">.</span>post<span class=\"token punctuation\">(</span>TOKEN_URL<span class=\"token punctuation\">,</span> data<span class=\"token operator\">=</span>token_data<span class=\"token punctuation\">)</span>\n    token_response <span class=\"token operator\">=</span> response<span class=\"token punctuation\">.</span>json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token comment\"># 4. Access Token 저장</span>\n    session<span class=\"token punctuation\">[</span><span class=\"token string\">'access_token'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> token_response<span class=\"token punctuation\">[</span><span class=\"token string\">'access_token'</span><span class=\"token punctuation\">]</span>\n    session<span class=\"token punctuation\">[</span><span class=\"token string\">'refresh_token'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> token_response<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'refresh_token'</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">return</span> <span class=\"token string\">\"Login successful!\"</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/data\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">get_data</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token comment\"># 5. Access Token으로 리소스 접근</span>\n    access_token <span class=\"token operator\">=</span> session<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'access_token'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> access_token<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> redirect<span class=\"token punctuation\">(</span><span class=\"token string\">\"/login\"</span><span class=\"token punctuation\">)</span>\n    \n    headers <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token string\">\"Authorization\"</span><span class=\"token punctuation\">:</span> <span class=\"token string-interpolation\"><span class=\"token string\">f\"Bearer </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>access_token<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">}</span>\n    response <span class=\"token operator\">=</span> requests<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"https://api.example.com/data\"</span><span class=\"token punctuation\">,</span> headers<span class=\"token operator\">=</span>headers<span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">return</span> response<span class=\"token punctuation\">.</span>json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"2-2-pkce-proof-key-for-code-exchange\" style=\"position:relative;\"><a href=\"#2-2-pkce-proof-key-for-code-exchange\" aria-label=\"2 2 pkce proof key for code exchange permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-2. PKCE (Proof Key for Code Exchange)</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> hashlib\n<span class=\"token keyword\">import</span> base64\n<span class=\"token keyword\">import</span> secrets\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">generate_code_verifier</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Code Verifier 생성\"\"\"</span>\n    <span class=\"token keyword\">return</span> base64<span class=\"token punctuation\">.</span>urlsafe_b64encode<span class=\"token punctuation\">(</span>secrets<span class=\"token punctuation\">.</span>token_bytes<span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span><span class=\"token string\">'utf-8'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>rstrip<span class=\"token punctuation\">(</span><span class=\"token string\">'='</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">generate_code_challenge</span><span class=\"token punctuation\">(</span>verifier<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Code Challenge 생성 (SHA256)\"\"\"</span>\n    challenge <span class=\"token operator\">=</span> hashlib<span class=\"token punctuation\">.</span>sha256<span class=\"token punctuation\">(</span>verifier<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token string\">'utf-8'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>digest<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> base64<span class=\"token punctuation\">.</span>urlsafe_b64encode<span class=\"token punctuation\">(</span>challenge<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span><span class=\"token string\">'utf-8'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>rstrip<span class=\"token punctuation\">(</span><span class=\"token string\">'='</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/login-pkce\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">login_pkce</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token comment\"># PKCE를 사용한 안전한 Authorization Code Flow</span>\n    code_verifier <span class=\"token operator\">=</span> generate_code_verifier<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    code_challenge <span class=\"token operator\">=</span> generate_code_challenge<span class=\"token punctuation\">(</span>code_verifier<span class=\"token punctuation\">)</span>\n    \n    session<span class=\"token punctuation\">[</span><span class=\"token string\">'code_verifier'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> code_verifier\n    state <span class=\"token operator\">=</span> secrets<span class=\"token punctuation\">.</span>token_urlsafe<span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span>\n    session<span class=\"token punctuation\">[</span><span class=\"token string\">'oauth_state'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> state\n    \n    params <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"response_type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"code\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">:</span> CLIENT_ID<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"redirect_uri\"</span><span class=\"token punctuation\">:</span> REDIRECT_URI<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"read write\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"state\"</span><span class=\"token punctuation\">:</span> state<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"code_challenge\"</span><span class=\"token punctuation\">:</span> code_challenge<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"code_challenge_method\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"S256\"</span>\n    <span class=\"token punctuation\">}</span>\n    \n    auth_url <span class=\"token operator\">=</span> <span class=\"token string-interpolation\"><span class=\"token string\">f\"</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>AUTHORIZATION_URL<span class=\"token punctuation\">}</span></span><span class=\"token string\">?</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>requests<span class=\"token punctuation\">.</span>compat<span class=\"token punctuation\">.</span>urlencode<span class=\"token punctuation\">(</span>params<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span>\n    <span class=\"token keyword\">return</span> redirect<span class=\"token punctuation\">(</span>auth_url<span class=\"token punctuation\">)</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/callback-pkce\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">callback_pkce</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    code <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"code\"</span><span class=\"token punctuation\">)</span>\n    state <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"state\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">if</span> state <span class=\"token operator\">!=</span> session<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'oauth_state'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token string\">\"Invalid state\"</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n    \n    <span class=\"token comment\"># Code Verifier와 함께 토큰 요청</span>\n    token_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"grant_type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"authorization_code\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"code\"</span><span class=\"token punctuation\">:</span> code<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"redirect_uri\"</span><span class=\"token punctuation\">:</span> REDIRECT_URI<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">:</span> CLIENT_ID<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"code_verifier\"</span><span class=\"token punctuation\">:</span> session<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'code_verifier'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    \n    response <span class=\"token operator\">=</span> requests<span class=\"token punctuation\">.</span>post<span class=\"token punctuation\">(</span>TOKEN_URL<span class=\"token punctuation\">,</span> data<span class=\"token operator\">=</span>token_data<span class=\"token punctuation\">)</span>\n    token_response <span class=\"token operator\">=</span> response<span class=\"token punctuation\">.</span>json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    \n    session<span class=\"token punctuation\">[</span><span class=\"token string\">'access_token'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> token_response<span class=\"token punctuation\">[</span><span class=\"token string\">'access_token'</span><span class=\"token punctuation\">]</span>\n    <span class=\"token keyword\">return</span> <span class=\"token string\">\"Login successful!\"</span></code></pre></div>\n<h2 id=\"3-client-credentials-flow\" style=\"position:relative;\"><a href=\"#3-client-credentials-flow\" aria-label=\"3 client credentials flow permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3. Client Credentials Flow</h2>\n<h3 id=\"3-1-서버-간-통신\" style=\"position:relative;\"><a href=\"#3-1-%EC%84%9C%EB%B2%84-%EA%B0%84-%ED%86%B5%EC%8B%A0\" aria-label=\"3 1 서버 간 통신 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3-1. 서버 간 통신</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> requests\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime<span class=\"token punctuation\">,</span> timedelta\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">OAuth2Client</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">__init__</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">,</span> client_id<span class=\"token punctuation\">,</span> client_secret<span class=\"token punctuation\">,</span> token_url<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        self<span class=\"token punctuation\">.</span>client_id <span class=\"token operator\">=</span> client_id\n        self<span class=\"token punctuation\">.</span>client_secret <span class=\"token operator\">=</span> client_secret\n        self<span class=\"token punctuation\">.</span>token_url <span class=\"token operator\">=</span> token_url\n        self<span class=\"token punctuation\">.</span>access_token <span class=\"token operator\">=</span> <span class=\"token boolean\">None</span>\n        self<span class=\"token punctuation\">.</span>token_expires_at <span class=\"token operator\">=</span> <span class=\"token boolean\">None</span>\n    \n    <span class=\"token keyword\">def</span> <span class=\"token function\">get_access_token</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token triple-quoted-string string\">\"\"\"Access Token 획득\"\"\"</span>\n        <span class=\"token comment\"># 토큰이 유효하면 재사용</span>\n        <span class=\"token keyword\">if</span> self<span class=\"token punctuation\">.</span>access_token <span class=\"token keyword\">and</span> self<span class=\"token punctuation\">.</span>token_expires_at<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">if</span> datetime<span class=\"token punctuation\">.</span>now<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">&lt;</span> self<span class=\"token punctuation\">.</span>token_expires_at<span class=\"token punctuation\">:</span>\n                <span class=\"token keyword\">return</span> self<span class=\"token punctuation\">.</span>access_token\n        \n        <span class=\"token comment\"># 새 토큰 요청</span>\n        token_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"grant_type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"client_credentials\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">:</span> self<span class=\"token punctuation\">.</span>client_id<span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"client_secret\"</span><span class=\"token punctuation\">:</span> self<span class=\"token punctuation\">.</span>client_secret<span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"api:read api:write\"</span>\n        <span class=\"token punctuation\">}</span>\n        \n        response <span class=\"token operator\">=</span> requests<span class=\"token punctuation\">.</span>post<span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">.</span>token_url<span class=\"token punctuation\">,</span> data<span class=\"token operator\">=</span>token_data<span class=\"token punctuation\">)</span>\n        token_response <span class=\"token operator\">=</span> response<span class=\"token punctuation\">.</span>json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        \n        self<span class=\"token punctuation\">.</span>access_token <span class=\"token operator\">=</span> token_response<span class=\"token punctuation\">[</span><span class=\"token string\">'access_token'</span><span class=\"token punctuation\">]</span>\n        expires_in <span class=\"token operator\">=</span> token_response<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'expires_in'</span><span class=\"token punctuation\">,</span> <span class=\"token number\">3600</span><span class=\"token punctuation\">)</span>\n        self<span class=\"token punctuation\">.</span>token_expires_at <span class=\"token operator\">=</span> datetime<span class=\"token punctuation\">.</span>now<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> timedelta<span class=\"token punctuation\">(</span>seconds<span class=\"token operator\">=</span>expires_in<span class=\"token punctuation\">)</span>\n        \n        <span class=\"token keyword\">return</span> self<span class=\"token punctuation\">.</span>access_token\n    \n    <span class=\"token keyword\">def</span> <span class=\"token function\">make_authenticated_request</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">,</span> url<span class=\"token punctuation\">,</span> method<span class=\"token operator\">=</span><span class=\"token string\">'GET'</span><span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token triple-quoted-string string\">\"\"\"인증된 요청\"\"\"</span>\n        token <span class=\"token operator\">=</span> self<span class=\"token punctuation\">.</span>get_access_token<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        headers <span class=\"token operator\">=</span> kwargs<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'headers'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n        headers<span class=\"token punctuation\">[</span><span class=\"token string\">'Authorization'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token string-interpolation\"><span class=\"token string\">f\"Bearer </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>token<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span>\n        kwargs<span class=\"token punctuation\">[</span><span class=\"token string\">'headers'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> headers\n        \n        <span class=\"token keyword\">return</span> requests<span class=\"token punctuation\">.</span>request<span class=\"token punctuation\">(</span>method<span class=\"token punctuation\">,</span> url<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># 사용 예시</span>\nclient <span class=\"token operator\">=</span> OAuth2Client<span class=\"token punctuation\">(</span>\n    client_id<span class=\"token operator\">=</span><span class=\"token string\">\"your-client-id\"</span><span class=\"token punctuation\">,</span>\n    client_secret<span class=\"token operator\">=</span><span class=\"token string\">\"your-client-secret\"</span><span class=\"token punctuation\">,</span>\n    token_url<span class=\"token operator\">=</span><span class=\"token string\">\"https://oauth-provider.com/token\"</span>\n<span class=\"token punctuation\">)</span>\n\nresponse <span class=\"token operator\">=</span> client<span class=\"token punctuation\">.</span>make_authenticated_request<span class=\"token punctuation\">(</span><span class=\"token string\">\"https://api.example.com/data\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">.</span>json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h2 id=\"4-jwt-json-web-token\" style=\"position:relative;\"><a href=\"#4-jwt-json-web-token\" aria-label=\"4 jwt json web token permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4. JWT (JSON Web Token)</h2>\n<h3 id=\"4-1-jwt-구조\" style=\"position:relative;\"><a href=\"#4-1-jwt-%EA%B5%AC%EC%A1%B0\" aria-label=\"4 1 jwt 구조 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-1. JWT 구조</h3>\n<p>JWT는 세 부분으로 구성된다:</p>\n<ol>\n<li><strong>Header</strong>: 토큰 타입과 알고리즘</li>\n<li><strong>Payload</strong>: 클레임 (사용자 정보, 권한 등)</li>\n<li><strong>Signature</strong>: 서명</li>\n</ol>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Header.Payload.Signature</code></pre></div>\n<h3 id=\"4-2-jwt-생성\" style=\"position:relative;\"><a href=\"#4-2-jwt-%EC%83%9D%EC%84%B1\" aria-label=\"4 2 jwt 생성 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-2. JWT 생성</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> jwt\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime<span class=\"token punctuation\">,</span> timedelta\n<span class=\"token keyword\">import</span> secrets\n\n<span class=\"token comment\"># JWT 설정</span>\nSECRET_KEY <span class=\"token operator\">=</span> secrets<span class=\"token punctuation\">.</span>token_urlsafe<span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span>\nALGORITHM <span class=\"token operator\">=</span> <span class=\"token string\">\"HS256\"</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">create_access_token</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">:</span> <span class=\"token builtin\">dict</span><span class=\"token punctuation\">,</span> expires_delta<span class=\"token punctuation\">:</span> timedelta <span class=\"token operator\">=</span> <span class=\"token boolean\">None</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Access Token 생성\"\"\"</span>\n    to_encode <span class=\"token operator\">=</span> data<span class=\"token punctuation\">.</span>copy<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">if</span> expires_delta<span class=\"token punctuation\">:</span>\n        expire <span class=\"token operator\">=</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> expires_delta\n    <span class=\"token keyword\">else</span><span class=\"token punctuation\">:</span>\n        expire <span class=\"token operator\">=</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> timedelta<span class=\"token punctuation\">(</span>minutes<span class=\"token operator\">=</span><span class=\"token number\">15</span><span class=\"token punctuation\">)</span>\n    \n    to_encode<span class=\"token punctuation\">.</span>update<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"exp\"</span><span class=\"token punctuation\">:</span> expire<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"iat\"</span><span class=\"token punctuation\">:</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"access\"</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    \n    encoded_jwt <span class=\"token operator\">=</span> jwt<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span>to_encode<span class=\"token punctuation\">,</span> SECRET_KEY<span class=\"token punctuation\">,</span> algorithm<span class=\"token operator\">=</span>ALGORITHM<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> encoded_jwt\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">create_refresh_token</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">:</span> <span class=\"token builtin\">dict</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Refresh Token 생성\"\"\"</span>\n    to_encode <span class=\"token operator\">=</span> data<span class=\"token punctuation\">.</span>copy<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    expire <span class=\"token operator\">=</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> timedelta<span class=\"token punctuation\">(</span>days<span class=\"token operator\">=</span><span class=\"token number\">30</span><span class=\"token punctuation\">)</span>\n    \n    to_encode<span class=\"token punctuation\">.</span>update<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"exp\"</span><span class=\"token punctuation\">:</span> expire<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"iat\"</span><span class=\"token punctuation\">:</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"refresh\"</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    \n    encoded_jwt <span class=\"token operator\">=</span> jwt<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span>to_encode<span class=\"token punctuation\">,</span> SECRET_KEY<span class=\"token punctuation\">,</span> algorithm<span class=\"token operator\">=</span>ALGORITHM<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> encoded_jwt\n\n<span class=\"token comment\"># 사용 예시</span>\nuser_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> <span class=\"token number\">123</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"username\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"alice\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"email\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"alice@example.com\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"user\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"admin\"</span><span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span>\n\naccess_token <span class=\"token operator\">=</span> create_access_token<span class=\"token punctuation\">(</span>user_data<span class=\"token punctuation\">,</span> expires_delta<span class=\"token operator\">=</span>timedelta<span class=\"token punctuation\">(</span>minutes<span class=\"token operator\">=</span><span class=\"token number\">15</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\nrefresh_token <span class=\"token operator\">=</span> create_refresh_token<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user_data<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string-interpolation\"><span class=\"token string\">f\"Access Token: </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>access_token<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string-interpolation\"><span class=\"token string\">f\"Refresh Token: </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>refresh_token<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"4-3-jwt-검증\" style=\"position:relative;\"><a href=\"#4-3-jwt-%EA%B2%80%EC%A6%9D\" aria-label=\"4 3 jwt 검증 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-3. JWT 검증</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> functools <span class=\"token keyword\">import</span> wraps\n<span class=\"token keyword\">from</span> flask <span class=\"token keyword\">import</span> request<span class=\"token punctuation\">,</span> jsonify\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">verify_token</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"JWT 토큰 검증\"\"\"</span>\n    <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n        payload <span class=\"token operator\">=</span> jwt<span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">,</span> SECRET_KEY<span class=\"token punctuation\">,</span> algorithms<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span>ALGORITHM<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> payload\n    <span class=\"token keyword\">except</span> jwt<span class=\"token punctuation\">.</span>ExpiredSignatureError<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>  <span class=\"token comment\"># 토큰 만료</span>\n    <span class=\"token keyword\">except</span> jwt<span class=\"token punctuation\">.</span>InvalidTokenError<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>  <span class=\"token comment\"># 유효하지 않은 토큰</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">token_required</span><span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"토큰 검증 데코레이터\"\"\"</span>\n    <span class=\"token decorator annotation punctuation\">@wraps</span><span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">decorated</span><span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>args<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        token <span class=\"token operator\">=</span> <span class=\"token boolean\">None</span>\n        \n        <span class=\"token comment\"># Authorization 헤더에서 토큰 추출</span>\n        <span class=\"token keyword\">if</span> <span class=\"token string\">'Authorization'</span> <span class=\"token keyword\">in</span> request<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">:</span>\n            auth_header <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">'Authorization'</span><span class=\"token punctuation\">]</span>\n            <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n                token <span class=\"token operator\">=</span> auth_header<span class=\"token punctuation\">.</span>split<span class=\"token punctuation\">(</span><span class=\"token string\">' '</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span>  <span class=\"token comment\"># \"Bearer &lt;token>\"</span>\n            <span class=\"token keyword\">except</span> IndexError<span class=\"token punctuation\">:</span>\n                <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">'message'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Invalid token format'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n        \n        <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> token<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">'message'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Token is missing'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n        \n        <span class=\"token comment\"># 토큰 검증</span>\n        payload <span class=\"token operator\">=</span> verify_token<span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> payload<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">'message'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Token is invalid or expired'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n        \n        <span class=\"token comment\"># 요청에 사용자 정보 추가</span>\n        request<span class=\"token punctuation\">.</span>current_user <span class=\"token operator\">=</span> payload\n        <span class=\"token keyword\">return</span> f<span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>args<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">return</span> decorated\n\n<span class=\"token comment\"># 사용 예시</span>\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/protected\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token decorator annotation punctuation\">@token_required</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">protected_route</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    user <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>current_user\n    <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token string\">'message'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Access granted'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'user_id'</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">'user_id'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'username'</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">'username'</span><span class=\"token punctuation\">]</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"4-4-rs256-알고리즘-비대칭-키\" style=\"position:relative;\"><a href=\"#4-4-rs256-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B9%84%EB%8C%80%EC%B9%AD-%ED%82%A4\" aria-label=\"4 4 rs256 알고리즘 비대칭 키 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-4. RS256 알고리즘 (비대칭 키)</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> cryptography<span class=\"token punctuation\">.</span>hazmat<span class=\"token punctuation\">.</span>primitives <span class=\"token keyword\">import</span> serialization\n<span class=\"token keyword\">from</span> cryptography<span class=\"token punctuation\">.</span>hazmat<span class=\"token punctuation\">.</span>primitives<span class=\"token punctuation\">.</span>asymmetric <span class=\"token keyword\">import</span> rsa\n<span class=\"token keyword\">import</span> jwt\n\n<span class=\"token comment\"># RSA 키 쌍 생성</span>\nprivate_key <span class=\"token operator\">=</span> rsa<span class=\"token punctuation\">.</span>generate_private_key<span class=\"token punctuation\">(</span>\n    public_exponent<span class=\"token operator\">=</span><span class=\"token number\">65537</span><span class=\"token punctuation\">,</span>\n    key_size<span class=\"token operator\">=</span><span class=\"token number\">2048</span>\n<span class=\"token punctuation\">)</span>\n\npublic_key <span class=\"token operator\">=</span> private_key<span class=\"token punctuation\">.</span>public_key<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># Private Key를 PEM 형식으로 저장</span>\nprivate_pem <span class=\"token operator\">=</span> private_key<span class=\"token punctuation\">.</span>private_bytes<span class=\"token punctuation\">(</span>\n    encoding<span class=\"token operator\">=</span>serialization<span class=\"token punctuation\">.</span>Encoding<span class=\"token punctuation\">.</span>PEM<span class=\"token punctuation\">,</span>\n    <span class=\"token builtin\">format</span><span class=\"token operator\">=</span>serialization<span class=\"token punctuation\">.</span>PrivateFormat<span class=\"token punctuation\">.</span>PKCS8<span class=\"token punctuation\">,</span>\n    encryption_algorithm<span class=\"token operator\">=</span>serialization<span class=\"token punctuation\">.</span>NoEncryption<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># Public Key를 PEM 형식으로 저장</span>\npublic_pem <span class=\"token operator\">=</span> public_key<span class=\"token punctuation\">.</span>public_bytes<span class=\"token punctuation\">(</span>\n    encoding<span class=\"token operator\">=</span>serialization<span class=\"token punctuation\">.</span>Encoding<span class=\"token punctuation\">.</span>PEM<span class=\"token punctuation\">,</span>\n    <span class=\"token builtin\">format</span><span class=\"token operator\">=</span>serialization<span class=\"token punctuation\">.</span>PublicFormat<span class=\"token punctuation\">.</span>SubjectPublicKeyInfo\n<span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># RS256으로 JWT 생성</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">create_token_rs256</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">:</span> <span class=\"token builtin\">dict</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"RS256 알고리즘으로 JWT 생성\"\"\"</span>\n    token <span class=\"token operator\">=</span> jwt<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span>\n        data<span class=\"token punctuation\">,</span>\n        private_pem<span class=\"token punctuation\">,</span>\n        algorithm<span class=\"token operator\">=</span><span class=\"token string\">\"RS256\"</span>\n    <span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> token\n\n<span class=\"token comment\"># RS256으로 JWT 검증</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">verify_token_rs256</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"RS256 알고리즘으로 JWT 검증\"\"\"</span>\n    <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n        payload <span class=\"token operator\">=</span> jwt<span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span>\n            token<span class=\"token punctuation\">,</span>\n            public_pem<span class=\"token punctuation\">,</span>\n            algorithms<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"RS256\"</span><span class=\"token punctuation\">]</span>\n        <span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> payload\n    <span class=\"token keyword\">except</span> jwt<span class=\"token punctuation\">.</span>InvalidTokenError<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>\n\n<span class=\"token comment\"># 사용 예시</span>\nuser_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> <span class=\"token number\">123</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"username\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"alice\"</span><span class=\"token punctuation\">}</span>\ntoken <span class=\"token operator\">=</span> create_token_rs256<span class=\"token punctuation\">(</span>user_data<span class=\"token punctuation\">)</span>\npayload <span class=\"token operator\">=</span> verify_token_rs256<span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span></code></pre></div>\n<h2 id=\"5-refresh-token-구현\" style=\"position:relative;\"><a href=\"#5-refresh-token-%EA%B5%AC%ED%98%84\" aria-label=\"5 refresh token 구현 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5. Refresh Token 구현</h2>\n<h3 id=\"5-1-refresh-token-플로우\" style=\"position:relative;\"><a href=\"#5-1-refresh-token-%ED%94%8C%EB%A1%9C%EC%9A%B0\" aria-label=\"5 1 refresh token 플로우 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5-1. Refresh Token 플로우</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> flask <span class=\"token keyword\">import</span> Flask<span class=\"token punctuation\">,</span> request<span class=\"token punctuation\">,</span> jsonify\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime<span class=\"token punctuation\">,</span> timedelta\n<span class=\"token keyword\">import</span> jwt\n\napp <span class=\"token operator\">=</span> Flask<span class=\"token punctuation\">(</span>__name__<span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># 토큰 저장소 (실제로는 데이터베이스 사용)</span>\ntoken_store <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">create_token_pair</span><span class=\"token punctuation\">(</span>user_data<span class=\"token punctuation\">:</span> <span class=\"token builtin\">dict</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Access Token과 Refresh Token 쌍 생성\"\"\"</span>\n    access_token <span class=\"token operator\">=</span> create_access_token<span class=\"token punctuation\">(</span>\n        user_data<span class=\"token punctuation\">,</span>\n        expires_delta<span class=\"token operator\">=</span>timedelta<span class=\"token punctuation\">(</span>minutes<span class=\"token operator\">=</span><span class=\"token number\">15</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span>\n    \n    refresh_token <span class=\"token operator\">=</span> create_refresh_token<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user_data<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token comment\"># Refresh Token 저장</span>\n    token_store<span class=\"token punctuation\">[</span>refresh_token<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user_data<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"created_at\"</span><span class=\"token punctuation\">:</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">return</span> access_token<span class=\"token punctuation\">,</span> refresh_token\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/refresh\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">refresh_token</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Refresh Token으로 새 Access Token 발급\"\"\"</span>\n    data <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>get_json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    refresh_token <span class=\"token operator\">=</span> data<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"refresh_token\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> refresh_token<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Refresh token is required\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n    \n    <span class=\"token comment\"># Refresh Token 검증</span>\n    payload <span class=\"token operator\">=</span> verify_token<span class=\"token punctuation\">(</span>refresh_token<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> payload <span class=\"token keyword\">or</span> payload<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"type\"</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">!=</span> <span class=\"token string\">\"refresh\"</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Invalid refresh token\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n    \n    <span class=\"token comment\"># Refresh Token이 저장소에 있는지 확인</span>\n    <span class=\"token keyword\">if</span> refresh_token <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> token_store<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Refresh token not found\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n    \n    <span class=\"token comment\"># 새 Access Token 생성</span>\n    user_id <span class=\"token operator\">=</span> payload<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span>\n    user_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user_id<span class=\"token punctuation\">}</span>  <span class=\"token comment\"># 실제로는 DB에서 조회</span>\n    \n    new_access_token <span class=\"token operator\">=</span> create_access_token<span class=\"token punctuation\">(</span>\n        user_data<span class=\"token punctuation\">,</span>\n        expires_delta<span class=\"token operator\">=</span>timedelta<span class=\"token punctuation\">(</span>minutes<span class=\"token operator\">=</span><span class=\"token number\">15</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"access_token\"</span><span class=\"token punctuation\">:</span> new_access_token\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/logout\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">logout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"로그아웃 (Refresh Token 무효화)\"\"\"</span>\n    data <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>get_json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    refresh_token <span class=\"token operator\">=</span> data<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"refresh_token\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">if</span> refresh_token <span class=\"token keyword\">in</span> token_store<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">del</span> token_store<span class=\"token punctuation\">[</span>refresh_token<span class=\"token punctuation\">]</span>\n    \n    <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"message\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Logged out successfully\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h2 id=\"6-oauth-20--jwt-통합\" style=\"position:relative;\"><a href=\"#6-oauth-20--jwt-%ED%86%B5%ED%95%A9\" aria-label=\"6 oauth 20  jwt 통합 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6. OAuth 2.0 + JWT 통합</h2>\n<h3 id=\"6-1-authorization-server-구현\" style=\"position:relative;\"><a href=\"#6-1-authorization-server-%EA%B5%AC%ED%98%84\" aria-label=\"6 1 authorization server 구현 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6-1. Authorization Server 구현</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> flask <span class=\"token keyword\">import</span> Flask<span class=\"token punctuation\">,</span> request<span class=\"token punctuation\">,</span> jsonify<span class=\"token punctuation\">,</span> redirect\n<span class=\"token keyword\">import</span> jwt\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime<span class=\"token punctuation\">,</span> timedelta\n\napp <span class=\"token operator\">=</span> Flask<span class=\"token punctuation\">(</span>__name__<span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># 클라이언트 정보 (실제로는 데이터베이스)</span>\nclients <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"client-id-123\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"client_secret\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"client-secret-456\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"redirect_uris\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"http://localhost:5000/callback\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"scopes\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"read\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"write\"</span><span class=\"token punctuation\">]</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\"># Authorization Code 저장소</span>\nauth_codes <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/authorize\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"GET\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">authorize</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Authorization Code 발급\"\"\"</span>\n    client_id <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">)</span>\n    redirect_uri <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"redirect_uri\"</span><span class=\"token punctuation\">)</span>\n    response_type <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"response_type\"</span><span class=\"token punctuation\">)</span>\n    scope <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">)</span>\n    state <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"state\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token comment\"># 클라이언트 검증</span>\n    <span class=\"token keyword\">if</span> client_id <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> clients<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"invalid_client\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n    \n    <span class=\"token keyword\">if</span> redirect_uri <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> clients<span class=\"token punctuation\">[</span>client_id<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"redirect_uris\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"invalid_redirect_uri\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n    \n    <span class=\"token keyword\">if</span> response_type <span class=\"token operator\">!=</span> <span class=\"token string\">\"code\"</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"unsupported_response_type\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n    \n    <span class=\"token comment\"># 사용자 인증 (실제로는 로그인 페이지)</span>\n    <span class=\"token comment\"># 여기서는 간단히 사용자 ID를 받는다고 가정</span>\n    user_id <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>args<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"123\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token comment\"># Authorization Code 생성</span>\n    <span class=\"token keyword\">import</span> secrets\n    auth_code <span class=\"token operator\">=</span> secrets<span class=\"token punctuation\">.</span>token_urlsafe<span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span>\n    auth_codes<span class=\"token punctuation\">[</span>auth_code<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">:</span> client_id<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user_id<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">:</span> scope<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"created_at\"</span><span class=\"token punctuation\">:</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"expires_in\"</span><span class=\"token punctuation\">:</span> <span class=\"token number\">600</span>  <span class=\"token comment\"># 10분</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token comment\"># 리다이렉트</span>\n    redirect_url <span class=\"token operator\">=</span> <span class=\"token string-interpolation\"><span class=\"token string\">f\"</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>redirect_uri<span class=\"token punctuation\">}</span></span><span class=\"token string\">?code=</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>auth_code<span class=\"token punctuation\">}</span></span><span class=\"token string\">&amp;state=</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>state<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span>\n    <span class=\"token keyword\">return</span> redirect<span class=\"token punctuation\">(</span>redirect_url<span class=\"token punctuation\">)</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/token\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">token</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Access Token 발급\"\"\"</span>\n    grant_type <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>form<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"grant_type\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">if</span> grant_type <span class=\"token operator\">==</span> <span class=\"token string\">\"authorization_code\"</span><span class=\"token punctuation\">:</span>\n        <span class=\"token comment\"># Authorization Code Flow</span>\n        code <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>form<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"code\"</span><span class=\"token punctuation\">)</span>\n        client_id <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>form<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">)</span>\n        client_secret <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>form<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"client_secret\"</span><span class=\"token punctuation\">)</span>\n        redirect_uri <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>form<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"redirect_uri\"</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token comment\"># Authorization Code 검증</span>\n        <span class=\"token keyword\">if</span> code <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> auth_codes<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"invalid_grant\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n        \n        auth_info <span class=\"token operator\">=</span> auth_codes<span class=\"token punctuation\">[</span>code<span class=\"token punctuation\">]</span>\n        \n        <span class=\"token comment\"># 만료 확인</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span> auth_info<span class=\"token punctuation\">[</span><span class=\"token string\">\"created_at\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>seconds <span class=\"token operator\">></span> auth_info<span class=\"token punctuation\">[</span><span class=\"token string\">\"expires_in\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">del</span> auth_codes<span class=\"token punctuation\">[</span>code<span class=\"token punctuation\">]</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"invalid_grant\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n        \n        <span class=\"token comment\"># 클라이언트 검증</span>\n        <span class=\"token keyword\">if</span> client_id <span class=\"token operator\">!=</span> auth_info<span class=\"token punctuation\">[</span><span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"invalid_client\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n        \n        <span class=\"token keyword\">if</span> client_secret <span class=\"token operator\">!=</span> clients<span class=\"token punctuation\">[</span>client_id<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"client_secret\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"invalid_client\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n        \n        <span class=\"token comment\"># JWT Access Token 생성</span>\n        user_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> auth_info<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">:</span> client_id<span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">:</span> auth_info<span class=\"token punctuation\">[</span><span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">]</span>\n        <span class=\"token punctuation\">}</span>\n        \n        access_token <span class=\"token operator\">=</span> create_access_token<span class=\"token punctuation\">(</span>user_data<span class=\"token punctuation\">,</span> timedelta<span class=\"token punctuation\">(</span>hours<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        refresh_token <span class=\"token operator\">=</span> create_refresh_token<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> auth_info<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token comment\"># Authorization Code 삭제</span>\n        <span class=\"token keyword\">del</span> auth_codes<span class=\"token punctuation\">[</span>code<span class=\"token punctuation\">]</span>\n        \n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"access_token\"</span><span class=\"token punctuation\">:</span> access_token<span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"token_type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Bearer\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"expires_in\"</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3600</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"refresh_token\"</span><span class=\"token punctuation\">:</span> refresh_token<span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">:</span> auth_info<span class=\"token punctuation\">[</span><span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">]</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">elif</span> grant_type <span class=\"token operator\">==</span> <span class=\"token string\">\"refresh_token\"</span><span class=\"token punctuation\">:</span>\n        <span class=\"token comment\"># Refresh Token Flow</span>\n        refresh_token <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>form<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"refresh_token\"</span><span class=\"token punctuation\">)</span>\n        client_id <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>form<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">)</span>\n        client_secret <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>form<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"client_secret\"</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token comment\"># Refresh Token 검증</span>\n        payload <span class=\"token operator\">=</span> verify_token<span class=\"token punctuation\">(</span>refresh_token<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> payload <span class=\"token keyword\">or</span> payload<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"type\"</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">!=</span> <span class=\"token string\">\"refresh\"</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"invalid_grant\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n        \n        <span class=\"token comment\"># 클라이언트 검증</span>\n        <span class=\"token keyword\">if</span> client_secret <span class=\"token operator\">!=</span> clients<span class=\"token punctuation\">[</span>client_id<span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"client_secret\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"invalid_client\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span>\n        \n        <span class=\"token comment\"># 새 Access Token 생성</span>\n        user_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> payload<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"client_id\"</span><span class=\"token punctuation\">:</span> client_id<span class=\"token punctuation\">}</span>\n        access_token <span class=\"token operator\">=</span> create_access_token<span class=\"token punctuation\">(</span>user_data<span class=\"token punctuation\">,</span> timedelta<span class=\"token punctuation\">(</span>hours<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        \n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"access_token\"</span><span class=\"token punctuation\">:</span> access_token<span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"token_type\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Bearer\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"expires_in\"</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3600</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">else</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"unsupported_grant_type\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">400</span></code></pre></div>\n<h3 id=\"6-2-resource-server-구현\" style=\"position:relative;\"><a href=\"#6-2-resource-server-%EA%B5%AC%ED%98%84\" aria-label=\"6 2 resource server 구현 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6-2. Resource Server 구현</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/user/profile\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token decorator annotation punctuation\">@token_required</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">get_user_profile</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"사용자 프로필 조회\"\"\"</span>\n    user <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>current_user\n    user_id <span class=\"token operator\">=</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span>\n    \n    <span class=\"token comment\"># 실제로는 데이터베이스에서 조회</span>\n    profile <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user_id<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"username\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"alice\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"email\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"alice@example.com\"</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span>profile<span class=\"token punctuation\">)</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/data\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"GET\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token decorator annotation punctuation\">@token_required</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">handle_data</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"리소스 접근\"\"\"</span>\n    user <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>current_user\n    \n    <span class=\"token comment\"># Scope 검증</span>\n    scopes <span class=\"token operator\">=</span> user<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"scope\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>split<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> <span class=\"token string\">\"read\"</span> <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> scopes <span class=\"token keyword\">and</span> request<span class=\"token punctuation\">.</span>method <span class=\"token operator\">==</span> <span class=\"token string\">\"GET\"</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"insufficient_scope\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">403</span>\n    \n    <span class=\"token keyword\">if</span> <span class=\"token string\">\"write\"</span> <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> scopes <span class=\"token keyword\">and</span> request<span class=\"token punctuation\">.</span>method <span class=\"token operator\">==</span> <span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"insufficient_scope\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">403</span>\n    \n    <span class=\"token keyword\">if</span> request<span class=\"token punctuation\">.</span>method <span class=\"token operator\">==</span> <span class=\"token string\">\"GET\"</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"data\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"some data\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">else</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"message\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Data created\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">201</span></code></pre></div>\n<h2 id=\"7-보안-모범-사례\" style=\"position:relative;\"><a href=\"#7-%EB%B3%B4%EC%95%88-%EB%AA%A8%EB%B2%94-%EC%82%AC%EB%A1%80\" aria-label=\"7 보안 모범 사례 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7. 보안 모범 사례</h2>\n<h3 id=\"7-1-토큰-보안\" style=\"position:relative;\"><a href=\"#7-1-%ED%86%A0%ED%81%B0-%EB%B3%B4%EC%95%88\" aria-label=\"7 1 토큰 보안 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7-1. 토큰 보안</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token comment\"># 1. HTTPS 사용 필수</span>\n<span class=\"token comment\"># 2. 토큰을 안전하게 저장 (HttpOnly Cookie)</span>\n<span class=\"token keyword\">from</span> flask <span class=\"token keyword\">import</span> make_response\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/login\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">login</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token comment\"># 로그인 처리</span>\n    user_data <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> <span class=\"token number\">123</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"username\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"alice\"</span><span class=\"token punctuation\">}</span>\n    access_token <span class=\"token operator\">=</span> create_access_token<span class=\"token punctuation\">(</span>user_data<span class=\"token punctuation\">)</span>\n    refresh_token <span class=\"token operator\">=</span> create_refresh_token<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user_data<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    \n    response <span class=\"token operator\">=</span> make_response<span class=\"token punctuation\">(</span>jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"message\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Login successful\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token comment\"># HttpOnly Cookie로 저장 (XSS 방지)</span>\n    response<span class=\"token punctuation\">.</span>set_cookie<span class=\"token punctuation\">(</span>\n        <span class=\"token string\">\"access_token\"</span><span class=\"token punctuation\">,</span>\n        access_token<span class=\"token punctuation\">,</span>\n        httponly<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span>\n        secure<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span>  <span class=\"token comment\"># HTTPS만</span>\n        samesite<span class=\"token operator\">=</span><span class=\"token string\">\"Strict\"</span><span class=\"token punctuation\">,</span>  <span class=\"token comment\"># CSRF 방지</span>\n        max_age<span class=\"token operator\">=</span><span class=\"token number\">900</span>  <span class=\"token comment\"># 15분</span>\n    <span class=\"token punctuation\">)</span>\n    \n    response<span class=\"token punctuation\">.</span>set_cookie<span class=\"token punctuation\">(</span>\n        <span class=\"token string\">\"refresh_token\"</span><span class=\"token punctuation\">,</span>\n        refresh_token<span class=\"token punctuation\">,</span>\n        httponly<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span>\n        secure<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span>\n        samesite<span class=\"token operator\">=</span><span class=\"token string\">\"Strict\"</span><span class=\"token punctuation\">,</span>\n        max_age<span class=\"token operator\">=</span><span class=\"token number\">2592000</span>  <span class=\"token comment\"># 30일</span>\n    <span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">return</span> response\n\n<span class=\"token comment\"># 3. 토큰 만료 시간 단축</span>\naccess_token <span class=\"token operator\">=</span> create_access_token<span class=\"token punctuation\">(</span>user_data<span class=\"token punctuation\">,</span> timedelta<span class=\"token punctuation\">(</span>minutes<span class=\"token operator\">=</span><span class=\"token number\">15</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># 4. 토큰 블랙리스트 (로그아웃 시)</span>\nblacklisted_tokens <span class=\"token operator\">=</span> <span class=\"token builtin\">set</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">is_token_blacklisted</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> <span class=\"token builtin\">bool</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">return</span> token <span class=\"token keyword\">in</span> blacklisted_tokens\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">verify_token_secure</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"보안 강화된 토큰 검증\"\"\"</span>\n    <span class=\"token comment\"># 블랙리스트 확인</span>\n    <span class=\"token keyword\">if</span> is_token_blacklisted<span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>\n    \n    <span class=\"token comment\"># 토큰 검증</span>\n    payload <span class=\"token operator\">=</span> verify_token<span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> payload<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>\n    \n    <span class=\"token comment\"># 추가 검증 (IP 주소, User-Agent 등)</span>\n    <span class=\"token comment\"># 실제로는 토큰에 포함된 정보와 요청 정보 비교</span>\n    \n    <span class=\"token keyword\">return</span> payload</code></pre></div>\n<h3 id=\"7-2-csrf-방지\" style=\"position:relative;\"><a href=\"#7-2-csrf-%EB%B0%A9%EC%A7%80\" aria-label=\"7 2 csrf 방지 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7-2. CSRF 방지</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> secrets\n\n<span class=\"token comment\"># CSRF 토큰 생성</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">generate_csrf_token</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">return</span> secrets<span class=\"token punctuation\">.</span>token_urlsafe<span class=\"token punctuation\">(</span><span class=\"token number\">32</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># CSRF 토큰 검증</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">verify_csrf_token</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">,</span> session_token<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-</span><span class=\"token operator\">></span> <span class=\"token builtin\">bool</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">return</span> token <span class=\"token operator\">==</span> session_token <span class=\"token keyword\">and</span> <span class=\"token builtin\">len</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token number\">0</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/sensitive-action\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token decorator annotation punctuation\">@token_required</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">sensitive_action</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"CSRF 보호가 필요한 액션\"\"\"</span>\n    csrf_token <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"X-CSRF-Token\"</span><span class=\"token punctuation\">)</span>\n    session_token <span class=\"token operator\">=</span> session<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"csrf_token\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> verify_csrf_token<span class=\"token punctuation\">(</span>csrf_token<span class=\"token punctuation\">,</span> session_token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Invalid CSRF token\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">403</span>\n    \n    <span class=\"token comment\"># 액션 수행</span>\n    <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"message\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Action completed\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"7-3-rate-limiting\" style=\"position:relative;\"><a href=\"#7-3-rate-limiting\" aria-label=\"7 3 rate limiting permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7-3. Rate Limiting</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> functools <span class=\"token keyword\">import</span> wraps\n<span class=\"token keyword\">from</span> collections <span class=\"token keyword\">import</span> defaultdict\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime<span class=\"token punctuation\">,</span> timedelta\n\n<span class=\"token comment\"># Rate Limiting 저장소</span>\nrate_limit_store <span class=\"token operator\">=</span> defaultdict<span class=\"token punctuation\">(</span><span class=\"token builtin\">list</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">rate_limit</span><span class=\"token punctuation\">(</span>max_requests<span class=\"token punctuation\">:</span> <span class=\"token builtin\">int</span> <span class=\"token operator\">=</span> <span class=\"token number\">5</span><span class=\"token punctuation\">,</span> window<span class=\"token punctuation\">:</span> <span class=\"token builtin\">int</span> <span class=\"token operator\">=</span> <span class=\"token number\">60</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"Rate Limiting 데코레이터\"\"\"</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">decorator</span><span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token decorator annotation punctuation\">@wraps</span><span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">def</span> <span class=\"token function\">decorated_function</span><span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>args<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n            <span class=\"token comment\"># 클라이언트 식별 (IP 주소 또는 사용자 ID)</span>\n            client_id <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>remote_addr\n            \n            now <span class=\"token operator\">=</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            window_start <span class=\"token operator\">=</span> now <span class=\"token operator\">-</span> timedelta<span class=\"token punctuation\">(</span>seconds<span class=\"token operator\">=</span>window<span class=\"token punctuation\">)</span>\n            \n            <span class=\"token comment\"># 윈도우 내 요청 수 확인</span>\n            requests_in_window <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span>\n                req_time <span class=\"token keyword\">for</span> req_time <span class=\"token keyword\">in</span> rate_limit_store<span class=\"token punctuation\">[</span>client_id<span class=\"token punctuation\">]</span>\n                <span class=\"token keyword\">if</span> req_time <span class=\"token operator\">></span> window_start\n            <span class=\"token punctuation\">]</span>\n            \n            <span class=\"token keyword\">if</span> <span class=\"token builtin\">len</span><span class=\"token punctuation\">(</span>requests_in_window<span class=\"token punctuation\">)</span> <span class=\"token operator\">>=</span> max_requests<span class=\"token punctuation\">:</span>\n                <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n                    <span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Rate limit exceeded\"</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string\">\"retry_after\"</span><span class=\"token punctuation\">:</span> window\n                <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">429</span>\n            \n            <span class=\"token comment\"># 요청 시간 기록</span>\n            rate_limit_store<span class=\"token punctuation\">[</span>client_id<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>append<span class=\"token punctuation\">(</span>now<span class=\"token punctuation\">)</span>\n            \n            <span class=\"token keyword\">return</span> f<span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>args<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> decorated_function\n    <span class=\"token keyword\">return</span> decorator\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/login\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token decorator annotation punctuation\">@rate_limit</span><span class=\"token punctuation\">(</span>max_requests<span class=\"token operator\">=</span><span class=\"token number\">5</span><span class=\"token punctuation\">,</span> window<span class=\"token operator\">=</span><span class=\"token number\">60</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">login</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token comment\"># 로그인 처리</span>\n    <span class=\"token keyword\">pass</span></code></pre></div>\n<h2 id=\"8-실전-예제\" style=\"position:relative;\"><a href=\"#8-%EC%8B%A4%EC%A0%84-%EC%98%88%EC%A0%9C\" aria-label=\"8 실전 예제 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>8. 실전 예제</h2>\n<h3 id=\"8-1-완전한-인증-시스템\" style=\"position:relative;\"><a href=\"#8-1-%EC%99%84%EC%A0%84%ED%95%9C-%EC%9D%B8%EC%A6%9D-%EC%8B%9C%EC%8A%A4%ED%85%9C\" aria-label=\"8 1 완전한 인증 시스템 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>8-1. 완전한 인증 시스템</h3>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> flask <span class=\"token keyword\">import</span> Flask<span class=\"token punctuation\">,</span> request<span class=\"token punctuation\">,</span> jsonify<span class=\"token punctuation\">,</span> session\n<span class=\"token keyword\">from</span> functools <span class=\"token keyword\">import</span> wraps\n<span class=\"token keyword\">import</span> jwt\n<span class=\"token keyword\">from</span> datetime <span class=\"token keyword\">import</span> datetime<span class=\"token punctuation\">,</span> timedelta\n\napp <span class=\"token operator\">=</span> Flask<span class=\"token punctuation\">(</span>__name__<span class=\"token punctuation\">)</span>\napp<span class=\"token punctuation\">.</span>secret_key <span class=\"token operator\">=</span> <span class=\"token string\">\"your-secret-key\"</span>\n\n<span class=\"token comment\"># 사용자 데이터베이스 (실제로는 DB 사용)</span>\nusers <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"alice\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span><span class=\"token string\">\"password\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"hashed_password\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"user\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"bob\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span><span class=\"token string\">\"password\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"hashed_password\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"user\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"admin\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">create_token</span><span class=\"token punctuation\">(</span>user_data<span class=\"token punctuation\">:</span> <span class=\"token builtin\">dict</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"JWT 토큰 생성\"\"\"</span>\n    payload <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user_data<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"username\"</span><span class=\"token punctuation\">:</span> user_data<span class=\"token punctuation\">[</span><span class=\"token string\">\"username\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">:</span> user_data<span class=\"token punctuation\">[</span><span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"exp\"</span><span class=\"token punctuation\">:</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> timedelta<span class=\"token punctuation\">(</span>hours<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"iat\"</span><span class=\"token punctuation\">:</span> datetime<span class=\"token punctuation\">.</span>utcnow<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">return</span> jwt<span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span>payload<span class=\"token punctuation\">,</span> app<span class=\"token punctuation\">.</span>secret_key<span class=\"token punctuation\">,</span> algorithm<span class=\"token operator\">=</span><span class=\"token string\">\"HS256\"</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">verify_token</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"JWT 토큰 검증\"\"\"</span>\n    <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n        payload <span class=\"token operator\">=</span> jwt<span class=\"token punctuation\">.</span>decode<span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">,</span> app<span class=\"token punctuation\">.</span>secret_key<span class=\"token punctuation\">,</span> algorithms<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"HS256\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> payload\n    <span class=\"token keyword\">except</span> jwt<span class=\"token punctuation\">.</span>InvalidTokenError<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">None</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">token_required</span><span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token decorator annotation punctuation\">@wraps</span><span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">decorated</span><span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>args<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        token <span class=\"token operator\">=</span> <span class=\"token boolean\">None</span>\n        <span class=\"token keyword\">if</span> <span class=\"token string\">\"Authorization\"</span> <span class=\"token keyword\">in</span> request<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">:</span>\n            token <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">\"Authorization\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>split<span class=\"token punctuation\">(</span><span class=\"token string\">\" \"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span>\n        \n        <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> token<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Token is missing\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n        \n        payload <span class=\"token operator\">=</span> verify_token<span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> payload<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Token is invalid\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n        \n        request<span class=\"token punctuation\">.</span>current_user <span class=\"token operator\">=</span> payload\n        <span class=\"token keyword\">return</span> f<span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>args<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> decorated\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">role_required</span><span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>roles<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token triple-quoted-string string\">\"\"\"역할 기반 접근 제어\"\"\"</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">decorator</span><span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token decorator annotation punctuation\">@wraps</span><span class=\"token punctuation\">(</span>f<span class=\"token punctuation\">)</span>\n        <span class=\"token decorator annotation punctuation\">@token_required</span>\n        <span class=\"token keyword\">def</span> <span class=\"token function\">decorated</span><span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>args<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n            user_roles <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>current_user<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> <span class=\"token builtin\">any</span><span class=\"token punctuation\">(</span>role <span class=\"token keyword\">in</span> user_roles <span class=\"token keyword\">for</span> role <span class=\"token keyword\">in</span> roles<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n                <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Insufficient permissions\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">403</span>\n            <span class=\"token keyword\">return</span> f<span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>args<span class=\"token punctuation\">,</span> <span class=\"token operator\">**</span>kwargs<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> decorated\n    <span class=\"token keyword\">return</span> decorator\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/login\"</span><span class=\"token punctuation\">,</span> methods<span class=\"token operator\">=</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">login</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    data <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>get_json<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    username <span class=\"token operator\">=</span> data<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"username\"</span><span class=\"token punctuation\">)</span>\n    password <span class=\"token operator\">=</span> data<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"password\"</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token comment\"># 사용자 인증 (실제로는 해시된 비밀번호 검증)</span>\n    <span class=\"token keyword\">if</span> username <span class=\"token keyword\">not</span> <span class=\"token keyword\">in</span> users<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Invalid credentials\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n    \n    user <span class=\"token operator\">=</span> users<span class=\"token punctuation\">[</span>username<span class=\"token punctuation\">]</span>\n    <span class=\"token comment\"># 실제로는 bcrypt 등으로 비밀번호 검증</span>\n    <span class=\"token keyword\">if</span> password <span class=\"token operator\">!=</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">\"password\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"error\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Invalid credentials\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">401</span>\n    \n    <span class=\"token comment\"># 토큰 생성</span>\n    token <span class=\"token operator\">=</span> create_token<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"username\"</span><span class=\"token punctuation\">:</span> username<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">]</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    \n    <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"access_token\"</span><span class=\"token punctuation\">:</span> token<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/profile\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token decorator annotation punctuation\">@token_required</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">get_profile</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    user <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span>current_user\n    <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">\"user_id\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"username\"</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">\"username\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">\"roles\"</span><span class=\"token punctuation\">]</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token decorator annotation punctuation\">@app<span class=\"token punctuation\">.</span>route</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/api/admin\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token decorator annotation punctuation\">@role_required</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"admin\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">def</span> <span class=\"token function\">admin_only</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">return</span> jsonify<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token string\">\"message\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Admin access granted\"</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h2 id=\"9-결론\" style=\"position:relative;\"><a href=\"#9-%EA%B2%B0%EB%A1%A0\" aria-label=\"9 결론 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>9. 결론</h2>\n<p>OAuth 2.0과 JWT는 현대적인 인증/인가 시스템의 핵심이다. 이 글에서 다룬 내용:</p>\n<ol>\n<li><strong>OAuth 2.0 플로우</strong>: Authorization Code, Client Credentials, PKCE</li>\n<li><strong>JWT 생성/검증</strong>: HS256, RS256 알고리즘</li>\n<li><strong>Refresh Token</strong>: 토큰 갱신 메커니즘</li>\n<li><strong>보안 모범 사례</strong>: HTTPS, HttpOnly Cookie, CSRF 방지, Rate Limiting</li>\n<li><strong>역할 기반 접근 제어</strong>: RBAC 구현</li>\n</ol>\n<p>이러한 기술들을 적절히 조합하면 안전하고 확장 가능한 인증/인가 시스템을 구축할 수 있다.</p>\n<h2 id=\"참고-자료\" style=\"position:relative;\"><a href=\"#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C\" aria-label=\"참고 자료 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>참고 자료</h2>\n<ul>\n<li><a href=\"https://oauth.net/2/\">OAuth 2.0 공식 스펙</a></li>\n<li><a href=\"https://jwt.io/\">JWT 공식 사이트</a></li>\n<li><a href=\"https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics\">OAuth 2.0 Security Best Practices</a></li>\n<li><a href=\"https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html\">OWASP Authentication Cheat Sheet</a></li>\n</ul>","tableOfContents":"<ul>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#oauth-20%EA%B3%BC-jwt-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5---%EC%9D%B8%EC%A6%9D%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C\">OAuth 2.0과 JWT 완전정복 - 인증/인가 실전 가이드</a></p>\n<ul>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#1-oauth-20-%EA%B8%B0%EC%B4%88\">1. OAuth 2.0 기초</a></p>\n<ul>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#1-1-oauth-20-%EA%B0%9C%EC%9A%94\">1-1. OAuth 2.0 개요</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#1-2-oauth-20-%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%A2%85%EB%A5%98\">1-2. OAuth 2.0 플로우 종류</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#2-authorization-code-flow\">2. Authorization Code Flow</a></p>\n<ul>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#2-1-%EA%B8%B0%EB%B3%B8-%ED%94%8C%EB%A1%9C%EC%9A%B0\">2-1. 기본 플로우</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#2-2-pkce-proof-key-for-code-exchange\">2-2. PKCE (Proof Key for Code Exchange)</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#3-client-credentials-flow\">3. Client Credentials Flow</a></p>\n<ul>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#3-1-%EC%84%9C%EB%B2%84-%EA%B0%84-%ED%86%B5%EC%8B%A0\">3-1. 서버 간 통신</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#4-jwt-json-web-token\">4. JWT (JSON Web Token)</a></p>\n<ul>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#4-1-jwt-%EA%B5%AC%EC%A1%B0\">4-1. JWT 구조</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#4-2-jwt-%EC%83%9D%EC%84%B1\">4-2. JWT 생성</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#4-3-jwt-%EA%B2%80%EC%A6%9D\">4-3. JWT 검증</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#4-4-rs256-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B9%84%EB%8C%80%EC%B9%AD-%ED%82%A4\">4-4. RS256 알고리즘 (비대칭 키)</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#5-refresh-token-%EA%B5%AC%ED%98%84\">5. Refresh Token 구현</a></p>\n<ul>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#5-1-refresh-token-%ED%94%8C%EB%A1%9C%EC%9A%B0\">5-1. Refresh Token 플로우</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#6-oauth-20--jwt-%ED%86%B5%ED%95%A9\">6. OAuth 2.0 + JWT 통합</a></p>\n<ul>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#6-1-authorization-server-%EA%B5%AC%ED%98%84\">6-1. Authorization Server 구현</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#6-2-resource-server-%EA%B5%AC%ED%98%84\">6-2. Resource Server 구현</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#7-%EB%B3%B4%EC%95%88-%EB%AA%A8%EB%B2%94-%EC%82%AC%EB%A1%80\">7. 보안 모범 사례</a></p>\n<ul>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#7-1-%ED%86%A0%ED%81%B0-%EB%B3%B4%EC%95%88\">7-1. 토큰 보안</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#7-2-csrf-%EB%B0%A9%EC%A7%80\">7-2. CSRF 방지</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#7-3-rate-limiting\">7-3. Rate Limiting</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#8-%EC%8B%A4%EC%A0%84-%EC%98%88%EC%A0%9C\">8. 실전 예제</a></p>\n<ul>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#8-1-%EC%99%84%EC%A0%84%ED%95%9C-%EC%9D%B8%EC%A6%9D-%EC%8B%9C%EC%8A%A4%ED%85%9C\">8-1. 완전한 인증 시스템</a></li>\n</ul>\n</li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#9-%EA%B2%B0%EB%A1%A0\">9. 결론</a></li>\n<li><a href=\"/etc/OAuth-2.0%EA%B3%BC-JWT-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%EA%B0%80-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C/#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C\">참고 자료</a></li>\n</ul>\n</li>\n</ul>","wordCount":{"words":283},"fields":{"slug":"/etc/OAuth-2.0과-JWT-완전정복-인증-인가-실전-가이드/","image":null,"faq":[]},"frontmatter":{"title":"OAuth 2.0과 JWT 완전정복 - 인증/인가 실전 가이드","date":"2025년 11월 28일","dateISO":"2025-11-28T00:00:00.000Z","updatedISO":null,"category":"etc","description":"OAuth 2.0과 JWT를 활용한 현대적인 인증/인가 시스템을 실전 예제와 함께 완벽하게 정리합니다. Authorization Code Flow, Implicit Flow, Client Credentials, JWT 생성/검증, 보안 모범 사례까지 모든 것을 다룹니다.","tags":["OAuth 2.0","JWT","인증","인가","보안","API","웹 개발","백엔드"]}}},"pageContext":{"slug":"/etc/OAuth-2.0과-JWT-완전정복-인증-인가-실전-가이드/","previous":{"fields":{"slug":"/javascript/TypeScript-완전정복-타입-시스템부터-고급-패턴까지/"},"frontmatter":{"title":"TypeScript 완전정복 - 타입 시스템부터 고급 패턴까지","tags":["TypeScript","타입 시스템","제네릭","유틸리티 타입","JavaScript","프론트엔드","웹 개발"]}},"next":{"fields":{"slug":"/etc/PostgreSQL-고급-기능-JSON-Full-Text-Search-Partitioning/"},"frontmatter":{"title":"PostgreSQL 고급 기능 - JSON, Full-Text Search, Partitioning","tags":["PostgreSQL","데이터베이스","JSON","Full-Text Search","Partitioning","인덱싱","성능 최적화","SQL"]}}}},"staticQueryHashes":["213619243","3262363727"]}