{"id":12151,"date":"2026-11-05T13:15:46","date_gmt":"2026-11-05T04:15:46","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12151"},"modified":"2026-11-05T13:48:27","modified_gmt":"2026-11-05T04:48:27","slug":"oauth-2-0-%eb%b3%b4%ec%95%88-%ea%b0%95%ed%99%94-rfc-8705mtls%ec%99%80-rfc-9449dpop-%ea%b7%b8%eb%a6%ac%ea%b3%a0-google%ec%9d%98-%ec%a0%81%ec%9a%a9-%eb%b0%a9%ec%8b%9d","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12151","title":{"rendered":"OAuth 2.0 \ubcf4\uc548 \uac15\ud654: RFC 8705(mTLS)\uc640 RFC 9449(DPoP), \uadf8\ub9ac\uace0 Google\uc758 \uc801\uc6a9 \ubc29\uc2dd"},"content":{"rendered":"<h1>OAuth 2.0 \ubcf4\uc548 \uac15\ud654: RFC 8705(mTLS)\uc640 RFC 9449(DPoP), \uadf8\ub9ac\uace0 Google\uc758 \uc801\uc6a9 \ubc29\uc2dd<\/h1>\n<h2>1. Introduction<\/h2>\n<p>OAuth 2.0\uc740 \ub2e4\uc591\ud55c \uc11c\ube44\uc2a4\uc5d0\uc11c API \uc811\uadfc \uad8c\ud55c\uc744 \uc704\uc784\ud558\uae30 \uc704\ud55c \ud45c\uc900 \ud504\ub85c\ud1a0\ucf5c\uc774\ub2e4. \uadf8\ub7ec\ub098 \uae30\ubcf8\uc801\uc778 OAuth 2.0\uc758 Access Token\uc740 Bearer Token \ubc29\uc2dd\uc73c\ub85c \ub3d9\uc791\ud558\uae30 \ub54c\ubb38\uc5d0, \ud1a0\ud070\uc774 \ud0c8\ucde8\ub418\uba74 \uacf5\uaca9\uc790\uac00 \ud574\ub2f9 \ud1a0\ud070\uc744 \uc774\uc6a9\ud574 API\ub97c \ud638\ucd9c\ud560 \uc218 \uc788\ub2e4\ub294 \ubcf4\uc548 \ubb38\uc81c\uac00 \uc874\uc7ac\ud55c\ub2e4.<\/p>\n<p>\uc774\ub7ec\ud55c \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud574 OAuth 2.0\uc5d0\uc11c\ub294 Access Token\uc744 \ud2b9\uc815 \ud074\ub77c\uc774\uc5b8\ud2b8\uc758 \uc554\ud638\ud559\uc801 \ud0a4\uc5d0 \uacb0\ud569\ud558\ub294 Sender-Constrained Token \ubc29\uc2dd\uc744 \ub3c4\uc785\ud588\ub2e4.<\/p>\n<p>\ub300\ud45c\uc801\uc778 \ud45c\uc900\uc774 \ub2e4\uc74c \ub450 \uac00\uc9c0 RFC\uc774\ub2e4.<\/p>\n<ul>\n<li><strong>RFC 8705<\/strong>: OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens<\/li>\n<li><strong>RFC 9449<\/strong>: OAuth 2.0 Demonstrating Proof of Possession (DPoP)<\/li>\n<\/ul>\n<p>\uc774 \uae00\uc5d0\uc11c\ub294 \ub450 \ud45c\uc900\uc758 \ub3d9\uc791 \uc6d0\ub9ac\uc640 \ucc28\uc774\uc810, \uadf8\ub9ac\uace0 Google OAuth\uc5d0\uc11c\uc758 \uc801\uc6a9 \ubc29\uc2dd\uc744 \uc0b4\ud3b4\ubcf8\ub2e4.<\/p>\n<hr \/>\n<h2>2. \uae30\uc874 OAuth 2.0\uc758 \ubb38\uc81c\uc810<\/h2>\n<p>\uc77c\ubc18\uc801\uc778 OAuth 2.0\uc5d0\uc11c Access Token\uc740 Bearer Token\uc774\ub2e4.<\/p>\n<pre><code class=\"language-http\">GET \/api\/account HTTP\/1.1\nHost: api.example.com\nAuthorization: Bearer access_token<\/code><\/pre>\n<p>Bearer Token\uc758 \ud575\uc2ec \ud2b9\uc131\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<blockquote>\n<p>\ud1a0\ud070\uc744 \uc18c\uc720\ud55c \ub204\uad6c\ub098 \ud574\ub2f9 \ud1a0\ud070\uc744 \uc0ac\uc6a9\ud560 \uc218 \uc788\ub2e4.<\/p>\n<\/blockquote>\n<p>\ub530\ub77c\uc11c Access Token\uc774 \ud0c8\ucde8\ub418\uba74 \uacf5\uaca9\uc790\ub294 \uc815\uc0c1 \ud074\ub77c\uc774\uc5b8\ud2b8\uc778 \uac83\ucc98\ub7fc API\ub97c \ud638\ucd9c\ud560 \uc218 \uc788\ub2e4.<\/p>\n<p>HTTPS\ub294 \uc804\uc1a1 \uad6c\uac04\uc5d0\uc11c \ud1a0\ud070\uc744 \ubcf4\ud638\ud558\uc9c0\ub9cc, \ud074\ub77c\uc774\uc5b8\ud2b8\ub098 \uc11c\ubc84\uc5d0\uc11c \ud1a0\ud070\uc774 \uc720\ucd9c\ub418\ub294 \uc0c1\ud669\uae4c\uc9c0 \ubc29\uc9c0\ud558\uc9c0\ub294 \ubabb\ud55c\ub2e4.<\/p>\n<p>\uc774\ub97c \ubcf4\uc644\ud558\uae30 \uc704\ud574 Sender-Constrained Token \ubc29\uc2dd\uc774 \ub4f1\uc7a5\ud588\ub2e4.<\/p>\n<h3>Sender-Constrained Token<\/h3>\n<p>Sender-Constrained Token\uc740 Access Token\uc744 \ud2b9\uc815 \uc554\ud638\ud559\uc801 \ud0a4\uc5d0 \ubc14\uc778\ub529\ud558\ub294 \ubc29\uc2dd\uc774\ub2e4.<\/p>\n<p>\ud1a0\ud070\uc744 \uc0ac\uc6a9\ud558\ub824\uba74 \ub2e4\uc74c \ub450 \uac00\uc9c0\uac00 \ubaa8\ub450 \ud544\uc694\ud558\ub2e4.<\/p>\n<ol>\n<li>Access Token<\/li>\n<li>\ud574\ub2f9 \ud1a0\ud070\uc5d0 \ubc14\uc778\ub529\ub41c \ud0a4\uc758 \uc18c\uc720 \uc99d\uba85<\/li>\n<\/ol>\n<p>\ub300\ud45c\uc801\uc778 \ubc29\uc2dd\uc774 mTLS\uc640 DPoP\uc774\ub2e4.<\/p>\n<hr \/>\n<h2>3. RFC 8705: Mutual TLS (mTLS)<\/h2>\n<h3>3.1 \uac1c\uc694<\/h3>\n<p>RFC 8705\ub294 OAuth 2.0\uc5d0\uc11c Mutual TLS\ub97c \ud65c\uc6a9\ud558\uc5ec Client\ub97c \uc778\uc99d\ud558\uace0 Access Token\uc744 \uc778\uc99d\uc11c\uc5d0 \ubc14\uc778\ub529\ud558\ub294 \ubc29\ubc95\uc744 \uc815\uc758\ud55c\ub2e4.<\/p>\n<p>RFC 8705\uc758 \uc8fc\uc694 \uae30\ub2a5\uc740 \ub2e4\uc74c \ub450 \uac00\uc9c0\ub2e4.<\/p>\n<ul>\n<li>OAuth 2.0 Mutual-TLS Client Authentication<\/li>\n<li>OAuth 2.0 Certificate-Bound Access Tokens<\/li>\n<\/ul>\n<p>\uacf5\uc2dd \ubb38\uc11c:<\/p>\n<p><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8705.html\">https:\/\/www.rfc-editor.org\/rfc\/rfc8705.html<\/a><\/p>\n<h3>3.2 Mutual TLS\ub780?<\/h3>\n<p>\uc77c\ubc18\uc801\uc778 TLS\uc5d0\uc11c\ub294 \uc11c\ubc84\uac00 \uc778\uc99d\uc11c\ub97c \uc81c\uc2dc\ud558\uace0 \ud074\ub77c\uc774\uc5b8\ud2b8\uac00 \uc11c\ubc84\ub97c \uc778\uc99d\ud55c\ub2e4.<\/p>\n<p>\ubc18\uba74 mTLS\uc5d0\uc11c\ub294 \ud074\ub77c\uc774\uc5b8\ud2b8\ub3c4 \uc778\uc99d\uc11c\ub97c \uc81c\uc2dc\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-text\">                  TLS Handshake\nClient  &lt;----------------------------&gt;  Server\n   |                                      |\n   |  Client Certificate                  |\n   |  Server Certificate                  |\n   |                                      |\n   +---------- Mutual Authentication ------+<\/code><\/pre>\n<p>\ud074\ub77c\uc774\uc5b8\ud2b8\ub294 \uc778\uc99d\uc11c\uc5d0 \ub300\uc751\ud558\ub294 Private Key\ub97c \uc18c\uc720\ud558\uace0 \uc788\uc74c\uc744 TLS Handshake \uacfc\uc815\uc5d0\uc11c \uc99d\uba85\ud55c\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c \uc11c\ubc84\ub294 \ub2e8\uc21c\ud788 \ud074\ub77c\uc774\uc5b8\ud2b8\uac00 \uc81c\uc2dc\ud55c \uc778\uc99d\uc11c\ub97c \ud655\uc778\ud558\ub294 \uac83\uc774 \uc544\ub2c8\ub77c, \uc2e4\uc81c Private Key \uc18c\uc720 \uc5ec\ubd80\uae4c\uc9c0 \ud655\uc778\ud560 \uc218 \uc788\ub2e4.<\/p>\n<h3>3.3 Certificate-Bound Access Token<\/h3>\n<p>RFC 8705\uc758 \ud575\uc2ec \uae30\ub2a5 \uc911 \ud558\ub098\ub294 Access Token\uc744 Client Certificate\uc5d0 \ubc14\uc778\ub529\ud558\ub294 \uac83\uc774\ub2e4.<\/p>\n<p>\uc608\ub97c \ub4e4\uc5b4 \ub2e4\uc74c\uacfc \uac19\uc740 \uad00\uacc4\uac00 \ub9cc\ub4e4\uc5b4\uc9c4\ub2e4.<\/p>\n<pre><code class=\"language-text\">Client Certificate: Cert-A\nAccess Token:      Token-A\n\nToken-A -&gt; Cert-A<\/code><\/pre>\n<p>Authorization Server\ub294 Access Token \ubc1c\uae09 \uc2dc \uc778\uc99d\uc11c\uc758 SHA-256 \uc9c0\ubb38 \ub4f1\uc744 Token\uc5d0 \uc5f0\uacb0\ud55c\ub2e4.<\/p>\n<p>\uc774\ud6c4 Resource Server\ub294 API \uc694\uccad\uc744 \ucc98\ub9ac\ud560 \ub54c \ub2e4\uc74c\uc744 \ud655\uc778\ud55c\ub2e4.<\/p>\n<ol>\n<li>Access Token\uc774 \uc720\ud6a8\ud55c\uac00?<\/li>\n<li>Access Token\uc5d0 \ubc14\uc778\ub529\ub41c \uc778\uc99d\uc11c\uc640 \ud604\uc7ac TLS \uc5f0\uacb0\uc758 Client Certificate\uc774 \uc77c\uce58\ud558\ub294\uac00?<\/li>\n<\/ol>\n<p>\uc778\uc99d\uc11c\uac00 \uc77c\uce58\ud558\uc9c0 \uc54a\uc73c\uba74 \uc694\uccad\uc744 \uac70\ubd80\ud55c\ub2e4.<\/p>\n<h3>3.4 API \uc694\uccad \uc608\uc2dc<\/h3>\n<pre><code class=\"language-http\">GET \/api\/account HTTP\/1.1\nHost: api.example.com\nAuthorization: Bearer Token-A<\/code><\/pre>\n<p>HTTP \uc694\uccad \uc790\uccb4\ub294 \uae30\uc874 Bearer Token \ubc29\uc2dd\uacfc \ub3d9\uc77c\ud558\ub2e4.<\/p>\n<p>\ucc28\uc774\uc810\uc740 HTTP Header\uc5d0 \ubcc4\ub3c4\uc758 DPoP Proof\ub97c \ucd94\uac00\ud558\uc9c0 \uc54a\ub294\ub2e4\ub294 \uc810\uc774\ub2e4.<\/p>\n<p>\ubcf4\uc548 \uac80\uc99d\uc740 TLS \uc5f0\uacb0\uc5d0\uc11c \uc218\ud589\ub41c\ub2e4.<\/p>\n<pre><code class=\"language-text\">Client\n  |\n  | TLS Handshake + Client Certificate\n  |\n  | Authorization: Bearer Token-A\n  |\nResource Server\n  |\n  +-- Token \uac80\uc99d\n  +-- Certificate Binding \uac80\uc99d\n  +-- API \ucc98\ub9ac<\/code><\/pre>\n<h3>3.5 RFC 8705\uc758 \ud2b9\uc9d5<\/h3>\n<ul>\n<li>TLS \uae30\ubc18 Client \uc778\uc99d<\/li>\n<li>\uc778\uc99d\uc11c \uae30\ubc18 Access Token \ubc14\uc778\ub529<\/li>\n<li>\ubcc4\ub3c4\uc758 Application-level Proof JWT \ubd88\ud544\uc694<\/li>\n<li>\uc778\uc99d\uc11c \uad00\ub9ac \ud544\uc694(PKI \ub610\ub294 Self-Signed \ubc29\uc2dd \uc120\ud0dd \uac00\ub2a5)<\/li>\n<li>\uc11c\ubc84 \uac04 \ud1b5\uc2e0 \ubc0f B2B \ud658\uacbd\uc5d0 \uc801\ud569<\/li>\n<\/ul>\n<p>\uc8fc\uc758\ud560 \uc810\uc740 mTLS Client Authentication\uacfc Certificate-Bound Access Token\uc740 \uc11c\ub85c \ub3c5\ub9bd\uc801\uc778 \uae30\ub2a5\uc774\ub77c\ub294 \uac83\uc774\ub2e4.<\/p>\n<p>mTLS\ub85c Client\ub97c \uc778\uc99d\ud55c\ub2e4\uace0 \ud574\uc11c Access Token\uc774 \uc790\ub3d9\uc73c\ub85c \uc778\uc99d\uc11c\uc5d0 \ubc14\uc778\ub529\ub418\ub294 \uac83\uc740 \uc544\ub2c8\ub2e4.<\/p>\n<hr \/>\n<h2>4. RFC 9449: DPoP<\/h2>\n<h3>4.1 \uac1c\uc694<\/h3>\n<p>DPoP\ub294 OAuth 2.0\uc5d0\uc11c Application Layer\uc758 \uc554\ud638\ud559\uc801 Proof\ub97c \uc0ac\uc6a9\ud558\uc5ec Access Token\uc744 \ud2b9\uc815 \ud0a4\uc5d0 \ubc14\uc778\ub529\ud558\ub294 \ubc29\uc2dd\uc774\ub2e4.<\/p>\n<p>\uacf5\uc2dd \ubb38\uc11c:<\/p>\n<p><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9449.html\">https:\/\/www.rfc-editor.org\/rfc\/rfc9449.html<\/a><\/p>\n<p>DPoP\ub294 TLS Client Certificate \ub300\uc2e0 Public Key\uc640 Private Key\ub97c \uc774\uc6a9\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-text\">Private Key -&gt; DPoP Proof \uc11c\uba85\nPublic Key  -&gt; Access Token Binding<\/code><\/pre>\n<p>Client\ub294 Private Key\ub97c \uc774\uc6a9\ud558\uc5ec DPoP Proof JWT\ub97c \uc0dd\uc131\ud558\uace0 HTTP Header\uc5d0 \ud3ec\ud568\ud55c\ub2e4.<\/p>\n<h3>4.2 DPoP \ub3d9\uc791 \ubc29\uc2dd<\/h3>\n<p>DPoP\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \ud750\ub984\uc73c\ub85c \ub3d9\uc791\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-text\">Client\n  |\n  | 1. Token Request + DPoP Proof\n  v\nAuthorization Server\n  |\n  | 2. Public Key\uc5d0 Token Binding\n  v\nClient\n  |\n  | 3. Access Token + DPoP Proof\n  v\nResource Server\n  |\n  | 4. Proof \uac80\uc99d\n  v\nAPI Response<\/code><\/pre>\n<h3>4.3 DPoP Proof JWT<\/h3>\n<p>DPoP Proof\ub294 JWT \ud615\uc2dd\uc73c\ub85c \uc0dd\uc131\ub41c\ub2e4.<\/p>\n<p>Header \uc608\uc2dc:<\/p>\n<pre><code class=\"language-json\">{\n  &quot;typ&quot;: &quot;dpop+jwt&quot;,\n  &quot;alg&quot;: &quot;ES256&quot;,\n  &quot;jwk&quot;: {\n    &quot;kty&quot;: &quot;EC&quot;,\n    &quot;crv&quot;: &quot;P-256&quot;,\n    &quot;x&quot;: &quot;...&quot;,\n    &quot;y&quot;: &quot;...&quot;\n  }\n}<\/code><\/pre>\n<p>\uc5ec\uae30\uc11c <code>jwk<\/code>\ub294 Client\uc758 Public Key\ub2e4.<\/p>\n<p>Private Key\ub294 JWT\uc5d0 \ud3ec\ud568\ub418\uc9c0 \uc54a\uc73c\uba70, \ud574\ub2f9 \ud0a4\ub85c JWT\uc5d0 \uc11c\uba85\ud55c\ub2e4.<\/p>\n<p>Payload \uc608\uc2dc:<\/p>\n<pre><code class=\"language-json\">{\n  &quot;jti&quot;: &quot;unique-id-123&quot;,\n  &quot;htm&quot;: &quot;GET&quot;,\n  &quot;htu&quot;: &quot;https:\/\/api.example.com\/api\/account&quot;,\n  &quot;iat&quot;: 1760000000,\n  &quot;ath&quot;: &quot;access_token_hash&quot;\n}<\/code><\/pre>\n<p>\uc8fc\uc694 Claim\uc758 \uc758\ubbf8\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<table>\n<thead>\n<tr>\n<th>Claim<\/th>\n<th>\uc758\ubbf8<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>jti<\/code><\/td>\n<td>Proof\uc758 \uace0\uc720 \uc2dd\ubcc4\uc790<\/td>\n<\/tr>\n<tr>\n<td><code>htm<\/code><\/td>\n<td>HTTP Method<\/td>\n<\/tr>\n<tr>\n<td><code>htu<\/code><\/td>\n<td>HTTP URI<\/td>\n<\/tr>\n<tr>\n<td><code>iat<\/code><\/td>\n<td>Proof \uc0dd\uc131 \uc2dc\uac01<\/td>\n<\/tr>\n<tr>\n<td><code>ath<\/code><\/td>\n<td>Access Token Hash<\/td>\n<\/tr>\n<tr>\n<td><code>nonce<\/code><\/td>\n<td>\uc11c\ubc84\uac00 \uc694\uad6c\ud558\ub294 \uacbd\uc6b0 \uc11c\ubc84 \uc81c\uacf5 nonce<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>4.4 Token \ubc1c\uae09 \uc694\uccad<\/h3>\n<p>Client\ub294 Authorization Server\uc5d0 Token \ubc1c\uae09\uc744 \uc694\uccad\ud558\uba74\uc11c DPoP Proof\ub97c \uc804\ub2ec\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-http\">POST \/token HTTP\/1.1\nHost: auth.example.com\nContent-Type: application\/x-www-form-urlencoded\nDPoP: eyJ...proof_jwt...\n\ngrant_type=authorization_code&amp;\ncode=abc123&amp;\nclient_id=my-client<\/code><\/pre>\n<p>Authorization Server\ub294 DPoP Proof\ub97c \uac80\uc99d\ud558\uace0 Access Token\uc744 \ud574\ub2f9 Public Key\uc5d0 \ubc14\uc778\ub529\ud55c\ub2e4.<\/p>\n<p>\uc751\ub2f5 \uc608\uc2dc:<\/p>\n<pre><code class=\"language-json\">{\n  &quot;access_token&quot;: &quot;eyJ...access_token...&quot;,\n  &quot;token_type&quot;: &quot;DPoP&quot;,\n  &quot;expires_in&quot;: 3600\n}<\/code><\/pre>\n<h3>4.5 API \ud638\ucd9c<\/h3>\n<p>Client\ub294 API \ud638\ucd9c \uc2dc Access Token\uacfc \uc0c8\ub85c\uc6b4 DPoP Proof\ub97c \ud568\uaed8 \uc804\ub2ec\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-http\">GET \/api\/account HTTP\/1.1\nHost: api.example.com\nAuthorization: DPoP eyJ...access_token...\nDPoP: eyJ...new_proof_jwt...<\/code><\/pre>\n<p>\ub450 \uac12\uc740 \uc11c\ub85c \ub2e4\ub978 \uc5ed\ud560\uc744 \ud55c\ub2e4.<\/p>\n<table>\n<thead>\n<tr>\n<th>JWT<\/th>\n<th>\uc5ed\ud560<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Access Token<\/td>\n<td>API \uc811\uadfc \uad8c\ud55c<\/td>\n<\/tr>\n<tr>\n<td>DPoP Proof<\/td>\n<td>Private Key \uc18c\uc720 \uc99d\uba85 \ubc0f \uc694\uccad \uc815\ubcf4 \uc99d\uba85<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Resource Server\ub294 DPoP Proof\uc758 \uc11c\uba85\uacfc Claim\uc744 \uac80\uc99d\ud55c\ub2e4.<\/p>\n<p>\uc8fc\uc694 \uac80\uc99d \ud56d\ubaa9\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<ul>\n<li>Proof\uc758 \uc11c\uba85\uc774 \uc62c\ubc14\ub978\uac00?<\/li>\n<li>\uc2e4\uc81c HTTP Method\uc640 <code>htm<\/code>\uc774 \uc77c\uce58\ud558\ub294\uac00?<\/li>\n<li>\uc2e4\uc81c \uc694\uccad URI\uc640 <code>htu<\/code>\uac00 \uc77c\uce58\ud558\ub294\uac00?<\/li>\n<li>Access Token Hash\uc640 <code>ath<\/code>\uac00 \uc77c\uce58\ud558\ub294\uac00?<\/li>\n<li>Access Token\uc5d0 \ubc14\uc778\ub529\ub41c Public Key\uc640 Proof\uc758 Public Key\uac00 \uc77c\uce58\ud558\ub294\uac00?<\/li>\n<li>Proof\uac00 \uc7ac\uc0ac\uc6a9\ub418\uac70\ub098 \ud5c8\uc6a9 \uc2dc\uac04 \ubc94\uc704\ub97c \ubc97\uc5b4\ub098\uc9c0 \uc54a\uc558\ub294\uac00?<\/li>\n<\/ul>\n<p>\uc774 \uac80\uc99d\uc744 \ud1b5\ud574 Access Token\ub9cc \ud0c8\ucde8\ud55c \uacf5\uaca9\uc790\ub294 API \ud638\ucd9c\uc744 \uc218\ud589\ud560 \uc218 \uc5c6\uac8c \ub41c\ub2e4.<\/p>\n<hr \/>\n<h2>5. RFC 8705\uc640 RFC 9449 \ube44\uad50<\/h2>\n<table>\n<thead>\n<tr>\n<th>\uad6c\ubd84<\/th>\n<th>RFC 8705 (mTLS)<\/th>\n<th>RFC 9449 (DPoP)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\ubcf4\ud638 \ubc29\uc2dd<\/td>\n<td>TLS Client Certificate<\/td>\n<td>Application-level Proof<\/td>\n<\/tr>\n<tr>\n<td>\ud0a4 \uc885\ub958<\/td>\n<td>X.509 Certificate + Private Key<\/td>\n<td>Public\/Private Key Pair<\/td>\n<\/tr>\n<tr>\n<td>\uc18c\uc720 \uc99d\uba85<\/td>\n<td>TLS Handshake<\/td>\n<td>DPoP Proof JWT<\/td>\n<\/tr>\n<tr>\n<td>Token Binding<\/td>\n<td>Client Certificate<\/td>\n<td>Public Key<\/td>\n<\/tr>\n<tr>\n<td>\uc694\uccad\ub9c8\ub2e4 Proof<\/td>\n<td>TLS \uc5f0\uacb0\uc5d0\uc11c \uc778\uc99d<\/td>\n<td>\ub9e4 HTTP \uc694\uccad\ub9c8\ub2e4 Proof \uc0dd\uc131<\/td>\n<\/tr>\n<tr>\n<td>HTTP Header<\/td>\n<td>Bearer Token<\/td>\n<td>DPoP Token + DPoP Proof<\/td>\n<\/tr>\n<tr>\n<td>Client \uc778\uc99d<\/td>\n<td>\uc9c0\uc6d0<\/td>\n<td>\uc790\uccb4\uc801\uc73c\ub85c\ub294 \uc9c0\uc6d0\ud558\uc9c0 \uc54a\uc74c<\/td>\n<\/tr>\n<tr>\n<td>\uc778\uc99d\uc11c \uad00\ub9ac<\/td>\n<td>\ud544\uc694<\/td>\n<td>\ubd88\ud544\uc694<\/td>\n<\/tr>\n<tr>\n<td>Browser SPA<\/td>\n<td>\uc0ac\uc2e4\uc0c1 \uc0ac\uc6a9 \ubd88\uac00<\/td>\n<td>\uc0c1\ub300\uc801\uc73c\ub85c \uc801\ud569<\/td>\n<\/tr>\n<tr>\n<td>Mobile App<\/td>\n<td>\uac00\ub2a5<\/td>\n<td>\uac00\ub2a5<\/td>\n<\/tr>\n<tr>\n<td>B2B API<\/td>\n<td>\uc801\ud569<\/td>\n<td>\uc801\ud569<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\ub450 \ubc29\uc2dd \ubaa8\ub450 Sender-Constrained Token\uc744 \uad6c\ud604\ud558\uc9c0\ub9cc, \uc18c\uc720 \uc99d\uba85 \ubc29\uc2dd\uacfc \uc6b4\uc601 \ubaa8\ub378\uc774 \ub2e4\ub974\ub2e4.<\/p>\n<hr \/>\n<h2>6. Google OAuth\uc5d0\uc11c\ub294 \uc5b4\ub5a4 \ubc29\uc2dd\uc744 \uc0ac\uc6a9\ud558\ub294\uac00?<\/h2>\n<p>Google OAuth\ub97c \uc774\ud574\ud560 \ub54c\ub294 Google\uc758 OAuth \uae30\ub2a5\uacfc RFC \ud45c\uc900\uc744 \uad6c\ubd84\ud574\uc11c \uc0b4\ud3b4\ubcfc \ud544\uc694\uac00 \uc788\ub2e4.<\/p>\n<h3>6.1 Google OAuth\uc758 \uae30\ubcf8 \uad6c\uc870<\/h3>\n<p>Google OAuth 2.0\uc740 \uc77c\ubc18\uc801\uc778 OAuth 2.0 Authorization Code Flow\ub97c \uc9c0\uc6d0\ud55c\ub2e4.<\/p>\n<p>\uc8fc\uc694 \ubcf4\uc548 \uae30\ub2a5\uc740 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<ul>\n<li>OAuth 2.0 Authorization Code Flow<\/li>\n<li>PKCE<\/li>\n<li>Client ID \uae30\ubc18 \uc560\ud50c\ub9ac\ucf00\uc774\uc158 \uc2dd\ubcc4<\/li>\n<li>Access Token \ubc0f Refresh Token<\/li>\n<li>OAuth \uc571 \uac80\uc99d \ubc0f \ub3d9\uc758 \ud654\uba74<\/li>\n<li>Token \uad00\ub9ac \ubc0f \ud3d0\uae30<\/li>\n<\/ul>\n<p>\uacf5\uc2dd \ubb38\uc11c:<\/p>\n<p><a href=\"https:\/\/developers.google.com\/identity\/protocols\/oauth2\">https:\/\/developers.google.com\/identity\/protocols\/oauth2<\/a><\/p>\n<h3>6.2 Google\uacfc DPoP<\/h3>\n<p>Google\uc740 DPoP\ub97c \uc9c0\uc6d0\ud558\ub294 OAuth \uae30\ub2a5\uc744 \uc81c\uacf5\ud55c\ub2e4.<\/p>\n<p>\ub2e4\ub9cc Google\uc758 DPoP \uc801\uc6a9\uc740 RFC 9449\uc758 \uc77c\ubc18\uc801\uc778 Access Token Sender-Constraining \ubc29\uc2dd\uacfc \ucc28\uc774\uac00 \uc788\ub2e4.<\/p>\n<p>Google\uc758 DPoP \uc801\uc6a9 \ubc29\uc2dd\uc5d0\uc11c\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \ud2b9\uc9d5\uc774 \uc788\ub2e4.<\/p>\n<table>\n<thead>\n<tr>\n<th>\ud56d\ubaa9<\/th>\n<th>Google\uc758 DPoP \uc801\uc6a9<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>DPoP<\/td>\n<td>\uc9c0\uc6d0<\/td>\n<\/tr>\n<tr>\n<td>Refresh Token Binding<\/td>\n<td>\uc9c0\uc6d0<\/td>\n<\/tr>\n<tr>\n<td>Refresh Token \uac31\uc2e0<\/td>\n<td>DPoP Proof \ud544\uc694<\/td>\n<\/tr>\n<tr>\n<td>Access Token<\/td>\n<td>Bearer Token \uc720\uc9c0<\/td>\n<\/tr>\n<tr>\n<td>Google API \ud638\ucd9c<\/td>\n<td>\uae30\uc874 Bearer \ubc29\uc2dd<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\uc989, Google\uc740 DPoP\ub97c \ud1b5\ud574 Refresh Token\uc744 \ud2b9\uc815 \ud0a4\uc5d0 \ubc14\uc778\ub529\ud558\uace0, Refresh Token \uac31\uc2e0 \uc2dc \ud574\ub2f9 \ud0a4\uc758 \uc18c\uc720 \uc99d\uba85\uc744 \uc694\uad6c\ud55c\ub2e4.<\/p>\n<p>\uc774 \ubc29\uc2dd\uc740 \uc7a5\uae30\uac04 \uc0ac\uc6a9\ub418\ub294 Refresh Token\uc774 \ud0c8\ucde8\ub418\uc5b4 \uc9c0\uc18d\uc801\uc778 \ud1a0\ud070 \ubc1c\uae09\uc5d0 \uc545\uc6a9\ub418\ub294 \uac83\uc744 \ubc29\uc9c0\ud558\ub294 \ub370 \ubaa9\uc801\uc774 \uc788\ub2e4.<\/p>\n<p>\uacf5\uc2dd \ubb38\uc11c:<\/p>\n<p><a href=\"https:\/\/developers.google.com\/identity\/protocols\/oauth2\/resources\/dpop-adoption\">https:\/\/developers.google.com\/identity\/protocols\/oauth2\/resources\/dpop-adoption<\/a><\/p>\n<h3>6.3 Google\uacfc mTLS<\/h3>\n<p>RFC 8705\ub294 OAuth Client \uc778\uc99d\uacfc Certificate-Bound Access Token\uc744 \uc704\ud55c \ud45c\uc900\uc774\ub2e4.<\/p>\n<p>Google\uc758 \uc77c\ubc18\uc801\uc778 OAuth 2.0 \ubc0f Google API \uc0ac\uc6a9 \ud750\ub984\uc5d0\uc11c\ub294 RFC 8705\uc758 Certificate-Bound Access Token\uc774 \uae30\ubcf8\uc801\uc778 Token Binding \ubc29\uc2dd\uc73c\ub85c \uc81c\uacf5\ub418\ub294 \uac83\uc740 \uc544\ub2c8\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c Google OAuth\uc5d0\uc11c mTLS\uac00 \uc77c\ubc18\uc801\uc73c\ub85c \uc0ac\uc6a9\ub41c\ub2e4\uace0 \uc774\ud574\ud558\ub294 \uac83\uc740 \uc815\ud655\ud558\uc9c0 \uc54a\ub2e4.<\/p>\n<hr \/>\n<h2>7. \ubcf4\uc548 \uad00\uc810\uc5d0\uc11c \ube44\uad50<\/h2>\n<table>\n<thead>\n<tr>\n<th>\uacf5\uaca9 \uc0c1\ud669<\/th>\n<th>Bearer Token<\/th>\n<th>mTLS<\/th>\n<th>DPoP<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Access Token \ud0c8\ucde8<\/td>\n<td>API \ud638\ucd9c \uac00\ub2a5<\/td>\n<td>\uc778\uc99d\uc11c Private Key \uc5c6\uc73c\uba74 \ubd88\uac00<\/td>\n<td>DPoP Private Key \uc5c6\uc73c\uba74 \ubd88\uac00<\/td>\n<\/tr>\n<tr>\n<td>Token \uc7ac\uc0ac\uc6a9<\/td>\n<td>\uac00\ub2a5<\/td>\n<td>\uc778\uc99d\uc11c Binding\uc73c\ub85c \uc81c\ud55c<\/td>\n<td>Proof \uac80\uc99d\uc73c\ub85c \uc81c\ud55c<\/td>\n<\/tr>\n<tr>\n<td>Client Private Key \ud0c8\ucde8<\/td>\n<td>\ud574\ub2f9 \uc5c6\uc74c<\/td>\n<td>\uc545\uc6a9 \uac00\ub2a5<\/td>\n<td>\uc545\uc6a9 \uac00\ub2a5<\/td>\n<\/tr>\n<tr>\n<td>Client \uc790\uccb4 \uc7a5\uc545<\/td>\n<td>\uc545\uc6a9 \uac00\ub2a5<\/td>\n<td>\uc545\uc6a9 \uac00\ub2a5<\/td>\n<td>\uc545\uc6a9 \uac00\ub2a5<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\ub450 \ubc29\uc2dd \ubaa8\ub450 Token\ub9cc \ud0c8\ucde8\ub418\ub294 \uc0c1\ud669\uc5d0\uc11c \ubcf4\uc548\uc744 \uac15\ud654\ud55c\ub2e4.<\/p>\n<p>\uadf8\ub7ec\ub098 Client\uc758 Private Key\uae4c\uc9c0 \ud0c8\ucde8\ub418\uac70\ub098 Client \uc790\uccb4\uac00 \uc7a5\uc545\ub418\uba74 \ubcf4\uc548 \ud6a8\uacfc\uac00 \uac10\uc18c\ud55c\ub2e4.<\/p>\n<p>DPoP\ub294 Proof\uc758 <code>jti<\/code>, <code>iat<\/code>, \uc11c\ubc84 nonce \ub4f1\uc744 \ud65c\uc6a9\ud558\uc5ec Replay \uacf5\uaca9\uc744 \ubc29\uc9c0\ud55c\ub2e4.<\/p>\n<p>mTLS\ub294 TLS Client Certificate\uacfc Access Token\uc744 \uacb0\ud569\ud558\uc5ec \ub2e4\ub978 Client\uc758 Token \uc7ac\uc0ac\uc6a9\uc744 \ubc29\uc9c0\ud55c\ub2e4.<\/p>\n<hr \/>\n<h2>8. \uc5b4\ub5a4 \ubc29\uc2dd\uc744 \uc120\ud0dd\ud574\uc57c \ud558\ub294\uac00?<\/h2>\n<h3>RFC 8705 (mTLS)\uac00 \uc801\ud569\ud55c \uacbd\uc6b0<\/h3>\n<ul>\n<li>\uae08\uc735\uae30\uad00 \ubc0f B2B API<\/li>\n<li>\uc11c\ubc84 \uac04 \ud1b5\uc2e0<\/li>\n<li>Client Certificate \uae30\ubc18 \uc778\uc99d \uccb4\uacc4<\/li>\n<li>\uc778\uc99d\uc11c \ubc1c\uae09 \ubc0f \uad00\ub9ac \uccb4\uacc4\uac00 \uc774\ubbf8 \uc874\uc7ac\ud558\ub294 \ud658\uacbd<\/li>\n<\/ul>\n<h3>RFC 9449 (DPoP)\uac00 \uc801\ud569\ud55c \uacbd\uc6b0<\/h3>\n<ul>\n<li>Mobile Application<\/li>\n<li>Browser SPA<\/li>\n<li>\uc778\uc99d\uc11c \ubc30\ud3ec\uac00 \uc5b4\ub824\uc6b4 Client \ud658\uacbd<\/li>\n<li>Application Layer\uc5d0\uc11c Token Binding\uc744 \uad6c\ud604\ud558\uace0 \uc2f6\uc740 \uacbd\uc6b0<\/li>\n<\/ul>\n<p>DPoP\ub294 \uc778\uc99d\uc11c \uae30\ubc18 TLS Client Authentication\uc5d0 \ube44\ud574 Client \uc778\uc99d\uc11c \uad00\ub9ac \ubd80\ub2f4\uc774 \uc801\ub2e4\ub294 \uc7a5\uc810\uc774 \uc788\ub2e4.<\/p>\n<hr \/>\n<h2>9. Conclusion<\/h2>\n<p>RFC 8705\uc640 RFC 9449\ub294 OAuth 2.0\uc758 Bearer Token\uc774 \uac00\uc9c4 \ud0c8\ucde8 \ubc0f \uc7ac\uc0ac\uc6a9 \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud55c Sender-Constrained Token \ud45c\uc900\uc774\ub2e4.<\/p>\n<p>\ud575\uc2ec \ucc28\uc774\ub294 \ub2e4\uc74c\uacfc \uac19\ub2e4.<\/p>\n<ul>\n<li>RFC 8705: TLS Client Certificate\uc744 \uc774\uc6a9\ud558\uc5ec Token\uc5d0 \ubc14\uc778\ub529\ub41c Private Key\uc758 \uc18c\uc720\ub97c \uc99d\uba85\ud55c\ub2e4.<\/li>\n<li>RFC 9449: Application Layer\uc758 DPoP Proof JWT\ub97c \uc774\uc6a9\ud558\uc5ec Token \uc18c\uc720\ub97c \uc99d\uba85\ud55c\ub2e4.<\/li>\n<\/ul>\n<p>Google\uc740 DPoP\ub97c Refresh Token \ubcf4\ud638\uc5d0 \ud65c\uc6a9\ud558\ub294 \ubc29\uc2dd\uc73c\ub85c \uc801\uc6a9\ud558\uace0 \uc788\uc73c\uba70, \uc77c\ubc18\uc801\uc778 Google API \ud638\ucd9c\uc5d0\uc11c\ub294 \uae30\uc874 Bearer Access Token \ubc29\uc2dd\uc744 \uc720\uc9c0\ud55c\ub2e4.<\/p>\n<p>\ub530\ub77c\uc11c OAuth \ubcf4\uc548 \uc544\ud0a4\ud14d\ucc98\ub97c \uc124\uacc4\ud560 \ub54c\ub294 Token \uc790\uccb4\uc758 \uc720\ud6a8\uc131\ubfd0 \uc544\ub2c8\ub77c Token\uc744 \uc0ac\uc6a9\ud558\ub294 Client\uc758 \uc18c\uc720 \uc99d\uba85\uae4c\uc9c0 \uace0\ub824\ud558\ub294 \uac83\uc774 \uc911\uc694\ud558\ub2e4.<\/p>\n<hr \/>\n<h2>References<\/h2>\n<ol>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc8705.html\">RFC 8705 &#8211; OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens<\/a><\/li>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9449.html\">RFC 9449 &#8211; OAuth 2.0 Demonstrating Proof of Possession (DPoP)<\/a><\/li>\n<li><a href=\"https:\/\/developers.google.com\/identity\/protocols\/oauth2\">Google OAuth 2.0 Documentation<\/a><\/li>\n<li><a href=\"https:\/\/developers.google.com\/identity\/protocols\/oauth2\/resources\/dpop-adoption\">Google DPoP Adoption Guide<\/a><\/li>\n<li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9700.html\">OAuth 2.0 Security Best Current Practice &#8211; RFC 9700<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>OAuth 2.0 \ubcf4\uc548 \uac15\ud654: RFC 8705(mTLS)\uc640 RFC 9449(DPoP), \uadf8\ub9ac\uace0 Google\uc758 \uc801\uc6a9 \ubc29\uc2dd 1. Introduction OAuth 2.0\uc740 \ub2e4\uc591\ud55c \uc11c\ube44\uc2a4\uc5d0\uc11c API \uc811\uadfc \uad8c\ud55c\uc744 \uc704\uc784\ud558\uae30 \uc704\ud55c \ud45c\uc900 \ud504\ub85c\ud1a0\ucf5c\uc774\ub2e4. \uadf8\ub7ec\ub098 \uae30\ubcf8\uc801\uc778 OAuth 2.0\uc758 Access Token\uc740 Bearer Token \ubc29\uc2dd\uc73c\ub85c \ub3d9\uc791\ud558\uae30 \ub54c\ubb38\uc5d0, \ud1a0\ud070\uc774 \ud0c8\ucde8\ub418\uba74 \uacf5\uaca9\uc790\uac00 \ud574\ub2f9 \ud1a0\ud070\uc744 \uc774\uc6a9\ud574 API\ub97c \ud638\ucd9c\ud560 \uc218 \uc788\ub2e4\ub294 \ubcf4\uc548 \ubb38\uc81c\uac00 \uc874\uc7ac\ud55c\ub2e4. \uc774\ub7ec\ud55c \ubb38\uc81c\ub97c \ud574\uacb0\ud558\uae30 \uc704\ud574 OAuth 2.0\uc5d0\uc11c\ub294\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=12151\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[],"class_list":["post-12151","post","type-post","status-publish","format-standard","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12151","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12151"}],"version-history":[{"count":2,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12151\/revisions"}],"predecessor-version":[{"id":12153,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/12151\/revisions\/12153"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12151"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12151"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12151"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}