โ† ๋ชฉ๋ก์œผ๋กœ
OAuth Deep Dive

OAuth 2.0 ์ด์ „์—๋Š” ์ œ3์ž ์•ฑ์ด ์‚ฌ์šฉ์ž์˜ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์ค€ ์œ„์ž„ ํ”„๋กœํ† ์ฝœ์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค. 2006~2007๋…„๊ฒฝ Twitter API๋ฅผ ์—ฐ๋™ํ•˜๋Š” ์„œ๋“œํŒŒํ‹ฐ ํด๋ผ์ด์–ธํŠธ๋“ค์€ ์‚ฌ์šฉ์ž์˜ Twitter ์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ง์ ‘ ์ž…๋ ฅ๋ฐ›์•„ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ–ˆ๊ณ , Flickr, Google, Yahoo! ๋“ฑ๋„ ๊ฐ์ž ๋…์ž์ ์ธ ์ธ์ฆ ์œ„์ž„ ๋ฐฉ์‹(FlickrAuth, AuthSub, BBAuth ๋“ฑ)์„ ์šด์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ง์ ‘ ๊ณต์œ ํ•˜๋Š” ํŒจํ„ด์€ ๊ตฌ์กฐ์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

  • ์ž๊ฒฉ ์ฆ๋ช… ๋…ธ์ถœ ๋ฒ”์œ„์˜ ํ™•๋Œ€: ์ œ3์ž ์•ฑ์ด ์นจํ•ด๋˜๋ฉด ์›๋ณธ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๊ทธ๋Œ€๋กœ ์œ ์ถœ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋™์ผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ”ผํ•ด๊ฐ€ ์—ฐ์‡„์ ์œผ๋กœ ํ™•์‚ฐ๋ฉ๋‹ˆ๋‹ค.
  • ๊ถŒํ•œ์˜ ๋น„๋ถ„๋ฆฌ(All-or-Nothing Access): ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๊ณ„์ • ์ „์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. "์ฝ๊ธฐ๋งŒ ํ—ˆ์šฉ" ๊ฐ™์€ ์„ธ๋ถ„ํ™”๋œ ๊ถŒํ•œ ์ œ์–ด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋…๋ฆฝ์  ํ•ด์ง€ ๋ถˆ๊ฐ€: ํŠน์ • ์•ฑ์˜ ์ ‘๊ทผ๋งŒ ์ฐจ๋‹จํ•˜๋ ค๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž์ฒด๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๊ณ , ๊ทธ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๋˜ ๋‹ค๋ฅธ ๋ชจ๋“  ์•ฑ๋„ ํ•จ๊ป˜ ๋Š๊น๋‹ˆ๋‹ค.
  • ๊ฐ์‚ฌ ์ถ”์  ๋ถ€์žฌ: ์–ด๋–ค ์•ฑ์ด ์–ธ์ œ, ์–ด๋–ค ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ–ˆ๋Š”์ง€ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์„œ๋น„์Šค ์ œ๊ณต์ž ์ž…์žฅ์—์„œ ์‚ฌ์šฉ์ž ๋ณธ์ธ์˜ ์ ‘๊ทผ๊ณผ ์ œ3์ž ์•ฑ์˜ ์ ‘๊ทผ์ด ๋™์ผํ•˜๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋“ค์€ ๋‹จ์ˆœํ•œ ๋ถˆํŽธํ•จ์ด ์•„๋‹ˆ๋ผ, ์„œ๋น„์Šค ์ƒํƒœ๊ณ„๊ฐ€ ํ™•์žฅ๋ ์ˆ˜๋ก ๋ณด์•ˆ ์‚ฌ๊ณ ์˜ ๊ทœ๋ชจ์™€ ๋นˆ๋„๊ฐ€ ์ฆ๊ฐ€ํ•˜๋Š” ๊ตฌ์กฐ์  ๊ฒฐํ•จ์ž…๋‹ˆ๋‹ค. OAuth 2.0(RFC 6749)์€ ๋ฆฌ์†Œ์Šค ์†Œ์œ ์ž์™€ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด์— ์ธ๊ฐ€ ๊ณ„์ธต(authorization layer)์„ ๋„์ž…ํ•˜์—ฌ, ๋น„๋ฐ€๋ฒˆํ˜ธ ์ง์ ‘ ๊ณต์œ ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋ฒ”์œ„์™€ ์ˆ˜๋ช…์ด ์ œํ•œ๋œ ์œ„์ž„ ์ž๊ฒฉ ์ฆ๋ช…(Access Token)์œผ๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์•„์ด๋””์–ด: ๊ฐ„์ ‘ ์œ„์ž„

OAuth์˜ ํ•ต์‹ฌ์€ ์ง์ ‘ ์ž๊ฒฉ ์ฆ๋ช… ๊ณต์œ ๋ฅผ ๊ฐ„์ ‘ ์œ„์ž„์œผ๋กœ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ตฌ์ฒด์ ์ธ ์˜ˆ์‹œ๋กœ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

[Before] ๋น„๋ฐ€๋ฒˆํ˜ธ ์ง์ ‘ ๊ณต์œ 
์‚ฌ์šฉ์ž โ”€โ”€(ID/PW ์ „๋‹ฌ)โ”€โ”€โ†’ ์ œ3์ž ์•ฑ โ”€โ”€(ID/PW๋กœ ๋กœ๊ทธ์ธ)โ”€โ”€โ†’ ์„œ๋น„์Šค API
                          โ†‘ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ €์žฅ        โ†‘ ์‚ฌ์šฉ์ž ๋ณธ์ธ๊ณผ ๊ตฌ๋ถ„ ๋ถˆ๊ฐ€

[After] OAuth ์œ„์ž„
์‚ฌ์šฉ์ž โ”€โ”€(์„œ๋น„์Šค์— ์ง์ ‘ ๋กœ๊ทธ์ธ)โ”€โ”€โ†’ Authorization Server โ”€โ”€(scope ์ œํ•œ๋œ ํ† ํฐ ๋ฐœ๊ธ‰)โ”€โ”€โ†’ ์ œ3์ž ์•ฑ
                                                                                    โ†“
                                                              Access Token์œผ๋กœ API ํ˜ธ์ถœ (์ œํ•œ๋œ ๊ถŒํ•œ, ์œ ํšจ๊ธฐ๊ฐ„ ์žˆ์Œ)

๋น„๋ฐ€๋ฒˆํ˜ธ ๊ณต์œ  ๋ชจ๋ธ์—์„œ ์‚ฌ์šฉ์ž์˜ ์ž๊ฒฉ ์ฆ๋ช…์€ ์ œ3์ž ์•ฑ์„ ๊ฒฝ์œ ํ•ฉ๋‹ˆ๋‹ค. OAuth ๋ชจ๋ธ์—์„œ ์‚ฌ์šฉ์ž๋Š” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” Authorization Server์— ์ง์ ‘ ์ธ์ฆํ•˜๊ณ , ์ œ3์ž ์•ฑ์—๋Š” ๋ฒ”์œ„์™€ ์ˆ˜๋ช…์ด ํ•œ์ •๋œ ํ† ํฐ๋งŒ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. ์ œ3์ž ์•ฑ์€ ์‚ฌ์šฉ์ž์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•Œ ์ˆ˜๋„ ์—†๊ณ , ์•Œ ํ•„์š”๋„ ์—†์Šต๋‹ˆ๋‹ค.

4๊ฐ€์ง€ ์—ญํ• 

OAuth 2.0 ํ”„๋กœํ† ์ฝœ์—๋Š” 4๊ฐ€์ง€ ์—ญํ• ์ด ์ฐธ์—ฌํ•ฉ๋‹ˆ๋‹ค.

์—ญํ• ์„ค๋ช…์˜ˆ์‹œ
Resource Owner๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•  ์ˆ˜ ์žˆ๋Š” ์ฃผ์ฒด. ๋ณดํ†ต ์ตœ์ข… ์‚ฌ์šฉ์ž๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ์— ํŒŒ์ผ์„ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž
Resource Server๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๊ณ , Access Token์„ ๊ฒ€์ฆํ•˜์—ฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋ฒ„๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ API ์„œ๋ฒ„
ClientResource Owner๋ฅผ ๋Œ€์‹ ํ•˜์—ฌ ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ ์—ฐ๋™ ๊ธฐ๋Šฅ์ด ์žˆ๋Š” ๋ฉ”๋ชจ ์•ฑ
Authorization ServerResource Owner๋ฅผ ์ธ์ฆํ•˜๊ณ , ์ธ๊ฐ€๋ฅผ ๋ฐ›์€ ํ›„ Access Token์„ ๋ฐœ๊ธ‰ํ•˜๋Š” ์„œ๋ฒ„๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„ (accounts.google.com)

Token๊ณผ Scope

Access Token

๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ์ž๊ฒฉ ์ฆ๋ช… ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค. ํŠน์ • ๋ฒ”์œ„(Scope)์™€ ์œ ํšจ ๊ธฐ๊ฐ„(Lifetime)์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. Resource Owner์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋Œ€์‹  ์ด ํ† ํฐ์œผ๋กœ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.

Refresh Token

Access Token์ด ๋งŒ๋ฃŒ๋˜์—ˆ์„ ๋•Œ, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋‹ค์‹œ ๋กœ๊ทธ์ธ์„ ์š”๊ตฌํ•˜์ง€ ์•Š๊ณ  ์ƒˆ Access Token์„ ๋ฐœ๊ธ‰๋ฐ›๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Refresh Token์€ Authorization Server์—๋งŒ ์ „๋‹ฌ๋˜๋ฉฐ, Resource Server์—๋Š” ์ „๋‹ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Scope

Client๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฆฌ์†Œ์Šค์˜ ๋ฒ”์œ„๋ฅผ ์ œํ•œํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. ๊ตฌ๊ธ€ OAuth์—์„œ drive.readonly scope๋ฅผ ์š”์ฒญํ•˜๋ฉด, ํ•ด๋‹น ์•ฑ์€ ๋“œ๋ผ์ด๋ธŒ๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•  ์ˆ˜ ์žˆ๊ณ  ์ˆ˜์ •์€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Access Token ๋ฐœ๊ธ‰ ์š”์ฒญ ์˜ˆ์‹œ:

scope=drive.readonly+calendar.events

โ†’ ๋“œ๋ผ์ด๋ธŒ ์ฝ๊ธฐ + ์บ˜๋ฆฐ๋” ์ด๋ฒคํŠธ ์ ‘๊ทผ๋งŒ ํ—ˆ์šฉ
โ†’ ๋“œ๋ผ์ด๋ธŒ ์“ฐ๊ธฐ, ๋ฉ”์ผ ์ ‘๊ทผ ๋“ฑ์€ ๋ถˆ๊ฐ€

์ธ๊ฐ€ ์Šน์ธ ์œ ํ˜• (Grant Types)

RFC 6749๋Š” 4๊ฐ€์ง€ ๊ธฐ๋ณธ Grant Type(Authorization Code, Implicit, Resource Owner Password Credentials, Client Credentials)์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ค‘ Implicit๊ณผ ROPC๋Š” ๋ณด์•ˆ ๋ฌธ์ œ๋กœ ํ˜„์žฌ ๋น„๊ถŒ์žฅ๋˜๋ฉฐ, ์ดํ›„ RFC 8628์ด Device Authorization Grant๋ฅผ ์ถ”๊ฐ€๋กœ ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ๋Š” ํ˜„์žฌ ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ์‹์„ ์ค‘์‹ฌ์œผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

Authorization Code Grant

๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋ณด์•ˆ์„ฑ์ด ๊ฐ€์žฅ ๋†’์€ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

[์‚ฌ์šฉ์ž] โ†’ [Client ์•ฑ] โ†’ [Authorization Server ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ]
                                      โ†“
                           ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ & ๋™์˜
                                      โ†“
                         Authorization Code๋ฅผ Client์—๊ฒŒ ์ „๋‹ฌ (redirect)
                                      โ†“
               Client๊ฐ€ Authorization Code๋ฅผ ์„œ๋ฒ„ ๊ฐ„ ํ†ต์‹ ์œผ๋กœ Access Token๊ณผ ๊ตํ™˜

ํ•ต์‹ฌ์€ Access Token์ด ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

  1. Client๊ฐ€ ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ Authorization Server์˜ /authorize ์—”๋“œํฌ์ธํŠธ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•ฉ๋‹ˆ๋‹ค.
  2. ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜๊ณ  Client์—๊ฒŒ ๊ถŒํ•œ์„ ๋ถ€์—ฌ(๋™์˜)ํ•ฉ๋‹ˆ๋‹ค.
  3. Authorization Server๊ฐ€ ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ Client์˜ redirect_uri๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๋ฉด์„œ Authorization Code๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  4. Client๋Š” ์ด Authorization Code๋ฅผ Authorization Server์˜ /token ์—”๋“œํฌ์ธํŠธ๋กœ ๋ณด๋‚ด์„œ Access Token์œผ๋กœ ๊ตํ™˜ํ•ฉ๋‹ˆ๋‹ค (์„œ๋ฒ„ ๊ฐ„ ๋ฐฑ์ฑ„๋„ ํ†ต์‹ ).

Authorization Code ์ž์ฒด๋Š” ์ผํšŒ์„ฑ์ด๋ฉฐ ์งง์€ ์œ ํšจ๊ธฐ๊ฐ„์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

Client Credentials Grant

์‚ฌ์šฉ์ž ๊ฐœ์ž… ์—†์ด, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž์ฒด์˜ ์ž๊ฒฉ ์ฆ๋ช…์œผ๋กœ Access Token์„ ๋ฐœ๊ธ‰๋ฐ›๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„ ๊ฐ„(M2M, Machine-to-Machine) ํ†ต์‹ ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

[Client] โ”€โ”€(client_id + client_secret)โ”€โ”€โ†’ [Authorization Server]
[Client] โ†โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€(Access Token)โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ [Authorization Server]

์‚ฌ์šฉ์ž๋ผ๋Š” ๊ฐœ๋…์ด ์—†์œผ๋ฏ€๋กœ, Client ์ž์ฒด๊ฐ€ ๋ฆฌ์†Œ์Šค์˜ ์†Œ์œ ์ž์ด๊ฑฐ๋‚˜ ์‚ฌ์ „์— ์ ‘๊ทผ ๊ถŒํ•œ์ด ๋ฐฐ์น˜๋œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋“œ์‹œ Confidential Client(๋น„๋ฐ€ํ‚ค๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋ฒ„ ์•ฑ)์—์„œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Device Authorization Grant (Device Code)

TV, IoT ๊ธฐ๊ธฐ, CLI ๋„๊ตฌ ๋“ฑ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์—†๊ฑฐ๋‚˜ ์ž…๋ ฅ์ด ์ œํ•œ๋œ ๋””๋ฐ”์ด์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. RFC 8628์— ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

[๋””๋ฐ”์ด์Šค] โ†’ Authorization Server์— Device Code ์š”์ฒญ
                  โ†“
        ํ™”๋ฉด์— URL๊ณผ ์ฝ”๋“œ๋ฅผ ํ‘œ์‹œ
        (์˜ˆ: "https://example.com/device ์—์„œ ์ฝ”๋“œ ABCD-1234๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”")
                  โ†“
[์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค๋ฅธ ๊ธฐ๊ธฐ(ํฐ/PC)์—์„œ ํ•ด๋‹น URL์— ์ ‘์†ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๋กœ๊ทธ์ธ]
                  โ†“
[๋””๋ฐ”์ด์Šค๊ฐ€ ์ฃผ๊ธฐ์ ์œผ๋กœ Authorization Server์— ํด๋งํ•˜์—ฌ Access Token ์ˆ˜์‹ ]

Legacy (๋น„๊ถŒ์žฅ)

Grant Type์„ค๋ช…๋น„๊ถŒ์žฅ ์‚ฌ์œ 
Implicit Grantํ† ํฐ์„ ๋ธŒ๋ผ์šฐ์ € URL ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ์ง์ ‘ ๋ฐ˜ํ™˜Access Token์ด ๋ธŒ๋ผ์šฐ์ € ํžˆ์Šคํ† ๋ฆฌ, ๋กœ๊ทธ ๋“ฑ์— ๋…ธ์ถœ. RFC 9700์—์„œ SHOULD NOT (์‚ฌ์šฉ ๋น„๊ถŒ์žฅ)
Resource Owner Password Credentials์‚ฌ์šฉ์ž์˜ ID/PW๋ฅผ Client๊ฐ€ ์ง์ ‘ ๋ฐ›์•„ ํ† ํฐ ์š”์ฒญOAuth๊ฐ€ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๊ทผ๋ณธ ๋ฌธ์ œ(๋น„๋ฐ€๋ฒˆํ˜ธ ์ง์ ‘ ๊ณต์œ )๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ฆ. RFC 9700์—์„œ MUST NOT (์‚ฌ์šฉ ๊ธˆ์ง€)

PKCE (Proof Key for Code Exchange)

Authorization Code Grant์—๋Š” ์ทจ์•ฝ์ ์ด ํ•˜๋‚˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋ฐ”์ผ ํ™˜๊ฒฝ์—์„œ ์•…์„ฑ ์•ฑ์ด ์ปค์Šคํ…€ URL ์Šคํ‚ด์„ ๊ฐ€๋กœ์ฑ„์„œ Authorization Code๋ฅผ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Authorization Server ์ž…์žฅ์—์„œ๋Š” ์ฝ”๋“œ๋ฅผ ์š”์ฒญํ•œ ์ •๋‹นํ•œ ์•ฑ๊ณผ ๊ฐ€๋กœ์ฑˆ ์•…์„ฑ ์•ฑ์„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

PKCE(๋ฐœ์Œ: "ํ”ฝ์‹œ")๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. RFC 7636์— ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉฐ, ์›๋ž˜๋Š” Public Client๋ฅผ ์œ„ํ•ด ์„ค๊ณ„๋˜์—ˆ์ง€๋งŒ ํ˜„์žฌ๋Š” ๋ชจ๋“  Client ์œ ํ˜•์— ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค. OAuth 2.1 ์ดˆ์•ˆ์—์„œ๋Š” ํ•„์ˆ˜ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ 1. Client๊ฐ€ code_verifier ์ƒ์„ฑ (43~128์ž ๋žœ๋ค ๋ฌธ์ž์—ด)           โ”‚
โ”‚                                                              โ”‚
โ”‚ 2. code_verifier โ†’ SHA-256 ํ•ด์‹œ โ†’ Base64URL ์ธ์ฝ”๋”ฉ             โ”‚
โ”‚    = code_challenge                                          โ”‚
โ”‚                                                              โ”‚
โ”‚ 3. /authorize ์š”์ฒญ ์‹œ code_challenge ์ „์†ก                      โ”‚
โ”‚    Authorization Server๊ฐ€ code_challenge ์ €์žฅ                  โ”‚
โ”‚                                                              โ”‚
โ”‚ 4. /token ์š”์ฒญ ์‹œ ์›๋ณธ code_verifier ์ „์†ก                       โ”‚
โ”‚    Authorization Server๊ฐ€ code_verifier๋ฅผ ํ•ด์‹œํ•˜์—ฌ              โ”‚
โ”‚    ์ €์žฅํ•ด๋‘” code_challenge์™€ ๋น„๊ต                               โ”‚
โ”‚                                                              โ”‚
โ”‚ 5. ์ผ์น˜ โ†’ Access Token ๋ฐœ๊ธ‰                                    โ”‚
โ”‚    ๋ถˆ์ผ์น˜ โ†’ ๊ฑฐ๋ถ€                                                โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

์•…์„ฑ ์•ฑ์ด Authorization Code๋ฅผ ๊ฐ€๋กœ์ฑ„๋”๋ผ๋„ code_verifier๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ํ† ํฐ ๊ตํ™˜์— ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. SHA-256์€ ๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ์ด๋ฏ€๋กœ code_challenge์—์„œ code_verifier๋ฅผ ์—ญ์‚ฐํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.

RFC 7636์€ code_challenge_method๋กœ S256(SHA-256)๊ณผ plain(ํ•ด์‹œ ์—†์ด code_verifier๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ) ๋‘ ๊ฐ€์ง€๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. S256์€ MTI(Mandatory To Implement)์ด๋ฉฐ, plain์€ ๊ธฐ์ˆ ์ ์œผ๋กœ SHA-256์„ ์ง€์›ํ•  ์ˆ˜ ์—†๋Š” ํ™˜๊ฒฝ์—์„œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. plain์€ code_verifier๊ฐ€ ์ „์†ก ์ค‘ ๋…ธ์ถœ๋˜๋ฉด ๋ณดํ˜ธ ํšจ๊ณผ๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ํŠน๋ณ„ํ•œ ์ œ์•ฝ์ด ์—†๋Š” ํ•œ ๋ฐ˜๋“œ์‹œ S256์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Client ์œ ํ˜•

RFC 6749๋Š” Client๋ฅผ ์ธ์ฆ ์ž๊ฒฉ ์ฆ๋ช…์˜ ๋ณด์•ˆ ์ˆ˜์ค€์— ๋”ฐ๋ผ ๋‘ ๊ฐ€์ง€๋กœ ๋ถ„๋ฅ˜ํ•ฉ๋‹ˆ๋‹ค.

์œ ํ˜•์„ค๋ช…์˜ˆ์‹œ
Confidential ClientClient Secret์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ผ์ด์–ธํŠธ. ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์›น ์•ฑ, ๋ฐฑ์—”๋“œ ์„œ๋น„์Šค
Public ClientClient Secret์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•  ์ˆ˜ ์—†๋Š” ํด๋ผ์ด์–ธํŠธ. ์†Œ์Šค ์ฝ”๋“œ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋…ธ์ถœSPA, ๋ชจ๋ฐ”์ผ ์•ฑ, ๋ฐ์Šคํฌํ†ฑ ์•ฑ

Public Client๋Š” Client Secret ์—†์ด ๋™์ž‘ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋ฐ˜๋“œ์‹œ PKCE๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

OAuth 2.0 vs OAuth 2.1 vs OpenID Connect

ํ•ญ๋ชฉOAuth 2.0 (RFC 6749)OAuth 2.1 (์ดˆ์•ˆ)OpenID Connect
๋ชฉ์ ์ธ๊ฐ€(Authorization)์ธ๊ฐ€(Authorization)์ธ์ฆ(Authentication) + ์ธ๊ฐ€
PKCE์„ ํƒํ•„์ˆ˜์„ ํƒ/๊ถŒ์žฅ
Implicit Grantํ—ˆ์šฉ์‚ญ์ œํ—ˆ์šฉ(๋น„๊ถŒ์žฅ)
Password Grantํ—ˆ์šฉ์‚ญ์ œํ•ด๋‹น ์—†์Œ
ํ•ต์‹ฌ ํ† ํฐAccess TokenAccess TokenAccess Token + ID Token

OAuth 2.0์ด "์ด ์•ฑ์ด ๋‚ด ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•ด๋„ ๋˜๋Š”๊ฐ€?"๋ผ๋Š” ์ธ๊ฐ€ ์งˆ๋ฌธ์— ๋‹ตํ•œ๋‹ค๋ฉด, OIDC๋Š” "์ด ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๊ตฌ์ธ๊ฐ€?"๋ผ๋Š” ์ธ์ฆ ์งˆ๋ฌธ์— ๋‹ตํ•ฉ๋‹ˆ๋‹ค. OIDC๋Š” ID Token(JWT ํ˜•์‹)์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ์‹ ์› ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๊ด€๋ จ RFC ๋งต

OAuth 2.0 ์ƒํƒœ๊ณ„๋Š” ํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ ์œ„์— ๋‹ค์–‘ํ•œ ๋ณด์กฐ ์ŠคํŽ™๋“ค๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

RFC/์ŠคํŽ™์ด๋ฆ„์—ญํ• 
RFC 6749OAuth 2.0 Frameworkํ•ต์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ
RFC 6750Bearer Token UsageAccess Token์„ HTTP ์š”์ฒญ์— ํฌํ•จํ•˜๋Š” ๋ฐฉ๋ฒ•
RFC 7636PKCEAuthorization Code ๊ฐ€๋กœ์ฑ„๊ธฐ ๋ฐฉ์–ด
RFC 7009Token Revocationํ† ํฐ ๋ฌดํšจํ™” ์—”๋“œํฌ์ธํŠธ
RFC 7662Token Introspectionํ† ํฐ ์œ ํšจ์„ฑ๊ณผ ๋ฉ”ํƒ€์ •๋ณด ์กฐํšŒ
RFC 8414Authorization Server MetadataOAuth ์—”๋“œํฌ์ธํŠธ ์ž๋™ ๊ฒ€์ƒ‰
RFC 8628Device Authorization Grant๋ธŒ๋ผ์šฐ์ € ์—†๋Š” ๋””๋ฐ”์ด์Šค์šฉ ์ธ๊ฐ€
RFC 9068JWT Profile for Access TokensAccess Token์„ JWT๋กœ ๊ตฌ์กฐํ™”
RFC 9700Security Best Current Practice๋ณด์•ˆ ๋ชจ๋ฒ” ์‚ฌ๋ก€ (Implicit/Password ๊ธˆ์ง€ ๋“ฑ)

๋ณด์•ˆ ๊ถŒ๊ณ ์‚ฌํ•ญ

RFC 9700 (OAuth 2.0 Security Best Current Practice)์—์„œ ๊ถŒ๊ณ ํ•˜๋Š” ํ•ต์‹ฌ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.

  1. ๋ชจ๋“  Client์— PKCE๋ฅผ ์‚ฌ์šฉํ•˜๋ผ. Public Client๋ฟ ์•„๋‹ˆ๋ผ Confidential Client์—์„œ๋„ ๊ถŒ์žฅํ•œ๋‹ค.
  2. Implicit Grant์™€ Password Grant๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ.
  3. Redirect URI๋ฅผ ์ •ํ™•ํžˆ ์ผ์น˜(exact match)์‹œ์ผœ๋ผ. ์™€์ผ๋“œ์นด๋“œ๋‚˜ ํŒจํ„ด ๋งค์นญ์€ ์˜คํ”ˆ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•˜๋‹ค.
  4. Refresh Token์€ ํ•œ ๋ฒˆ ์‚ฌ์šฉ ํ›„ ์ƒˆ ๊ฒƒ์œผ๋กœ ๊ต์ฒด(Rotation)ํ•˜๋ผ. ํƒˆ์ทจ๋œ Refresh Token์˜ ์žฌ์‚ฌ์šฉ์„ ํƒ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  5. Access Token์˜ ์œ ํšจ๊ธฐ๊ฐ„์„ ์งง๊ฒŒ(์ˆ˜ ๋ถ„~1์‹œ๊ฐ„) ์„ค์ •ํ•˜๊ณ , Refresh Token์œผ๋กœ ๊ฐฑ์‹ ํ•˜๋ผ.
  6. state ํŒŒ๋ผ๋ฏธํ„ฐ ๋˜๋Š” PKCE๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CSRF๋ฅผ ๋ฐฉ์–ดํ•˜๋ผ.
  7. ๋ชจ๋“  ํ†ต์‹ ์— TLS(HTTPS)๋ฅผ ์‚ฌ์šฉํ•˜๋ผ.

References