๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring Boot

[OAuth] OAuth๋ž€? ํ๋ฆ„, ์šฉ์–ด ์ •๋ฆฌ

by ์šฐ์ฃผ๋ฌผ๊ณ ๊ธฐ 2025. 5. 7.
๋ฐ˜์‘ํ˜•

OAuth๊ฐ€ ๋ญ˜๊นŒ?

OAuth๋Š” ์ œ 3์˜ ์„œ๋น„์Šค์— ๊ณ„์ • ๊ด€๋ฆฌ๋ฅผ ๋งก๊ธฐ๋Š” ๋ฐฉ์‹์ž„.

ex) ์นด์นด์˜ค๋กœ ๋กœ๊ทธ์ธํ•˜๊ธฐ, ๋„ค์ด๋ฒ„๋กœ ๋กœ๊ทธ์ธํ•˜๊ธฐ ๋“ฑ๋“ฑ..

 

OAuth ์šฉ์–ด ์ •๋ฆฌ๋จผ์ € ํ•˜๊ฒ ์Œ.

 

๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ(resource owner)

์ธ์ฆ ์„œ๋ฒ„์— ์ž์‹ ์˜ ์ •๋ณด์‚ฌ์šฉ์„ ํ—ˆ๊ฐ€ํ•˜๋Š” ์ฃผ์ฒด.

์„œ๋น„์Šค ์ด์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ์ž„.

 

๋ฆฌ์†Œ์Šค ์„œ๋ฒ„(resource server)

๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ , ์˜ค๋„ˆ์˜ ์ •๋ณด๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ์ฃผ์ฒด.

๋„ค์ด๋ฒ„, ์นด์นด์˜ค, ๊ตฌ๊ธ€์ด ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์ž„.

 

์ธ์ฆ ์„œ๋ฒ„(Authorization server)

ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ์˜ ์ •๋ณด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ† ํฐ ๋ฐœ๊ธ‰ํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

(์‹ค์ œ ์šด์˜์—์„œ๋Š” ์นด์นด์˜ค๊ฐ™์€ ๊ธฐ๊ด€์ด ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„, ์ธ์ฆ์„œ๋ฒ„ ์—ญํ•  ๋™์‹œ์— ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ)

 

ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(Client Application)

์ธ์ฆ ์„œ๋ฒ„ํ•œํ…Œ ์ธ์ฆ ๋ฐ›๊ณ , ๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์“ฐ๋Š” ์ฃผ์ฒด

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“œ๋Š” ํ”„๋กœ๊ทธ๋žจ.

 

 

 


 

OAuth ์“ฐ๋ฉด ์ธ์ฆ ์„œ๋ฒ„(์นด์นด์˜ค)์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ Token์‚ฌ์šฉํ•ด์„œ

๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์—์„œ ์˜ค๋„ˆ์˜ ์ •๋ณด ์š”์ฒญํ•˜๊ณ  ์‘๋‹ต๋ฐ›์•„์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ.

 

๊ทผ๋ฐ ์–ด๋–ป๊ฒŒ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ์˜ ์ •๋ณด๋ฅผ ์ทจ๋“ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

๋ฐฉ๋ฒ•์€ 4๊ฐ€์ง€์ž„

 

โœ…๊ถŒํ•œ ๋ถ€์—ฌ ์ฝ”๋“œ ์Šน์ธ ํƒ€์ž…

OAuth2.0์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ด๋Š” ๋ฐฉ๋ฒ•

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผํ• ๋•Œ ์“ฐ์ด๊ณ ,

๊ถŒํ•œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ & ๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ์— ๋Œ€ํ•œ ์—‘์„ธ์Šค ํ† ํฐ

๋ฐœ๊ธ‰ ๋ฐ›๋Š” ๋ฐฉ์‹

 

โœ…์•”์‹œ์  ์Šน์ธ ํƒ€์ž…

์„œ๋ฒ„๊ฐ€ ์—†๋Š” ์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ์›น app์—์„œ ์ฃผ๋กœ ์“ฐ๋Š” ๋ฐฉ๋ฒ•

 

โœ…๋ฆฌ์†Œ์Šค ์†Œ์œ ์ž ์•”ํ˜ธ ์ž๊ฒฉ์ฆ๋ช… ์Šน์ธ ํƒ€์ž…

โœ…ํด๋ผ์ด์–ธํŠธ ์ž๊ฒฉ์ฆ๋ช… ์Šน์ธ ํƒ€์ž…

 

 

 

 

**๊ถŒํ•œ ๋ถ€์—ฌ ์ฝ”๋“œ ์Šน์ธ ํƒ€์ž…๋งŒ ์•Œ๋ฉด ๋ ๋“ฏ

๊ทธ๊ฒƒ๋งŒ ํฌ์ŠคํŒ… ํ•˜๊ฒ ์Œ!


 

๊ถŒํ•œ ๋ถ€์—ฌ ์ฝ”๋“œ ์Šน์ธ ํƒ€์ž… (Authorization code grant type)

 

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

๋ฆฌ์†Œ์Šค ์„œ๋ฒ„ (์ž์›์„ ๊ฐ–๊ณ  ์žˆ๋Š” ์• )

์ธ์ฆ ์„œ๋ฒ„ (ํ† ํฐ ๋ฐœ๊ธ‰ํ•ด์ฃผ๋Š” ์—ญํ• )

๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ (๋กœ๊ทธ์ธํ•˜๋ ค๋Š” ์‚ฌ์šฉ์ž)

 

์ด ๋„ค๊ฐ€์ง€๊ฐ€ ์–ด๋–ค ์ˆœ์„œ๋กœ ์ผํ•˜๋Š”์ง€ ์•Œ์•„์•ผ๋จ.

 

 

 

๊ถŒํ•œ ์š”์ฒญ์ด๋ž€?

 

ํด๋ผ์ด์–ธํŠธ(์Šคํ”„๋ง๋ถ€ํŠธ ์„œ๋ฒ„)๊ฐ€ ์นด์นด์˜ค๊ฐ™์€ ๊ถŒํ•œ ์„œ๋ฒ„์—

ํŠน์ • ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ๊ถŒํ•œ์„ ์š”์ฒญํ•˜๋Š”๊ฒƒ์ž„.

 

์š”์ฒญ URI๋Š” ์„œ๋ฒ„๋งˆ๋‹ค ๋‹ค๋ฅด์ง€๋งŒ ๋ณดํ†ต์€

ํด๋ผ์ด์–ธํŠธID, ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ URI, ์‘๋‹ต ํƒ€์ž…

์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ณด๋ƒ„

 

์‚ฌ์šฉ์ž๊ฐ€ "์นด์นด์˜ค ๋กœ๊ทธ์ธ" ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ธ์ฆ ์„œ๋ฒ„๋กœ

์•„๋ž˜์™€ ๊ฐ™์ด GET ์š”์ฒญ ๋ณด๋‚ด๋Š”๊ฑฐ์ž„.

GET spring-authorization-server.example/authorize=?
    client_id=66a36b4c2&
    redirect_uri=http://locationhost:8080/oauth/kakao/callback
    response_type=code&   // ์ธ๊ฐ€ ์ฝ”๋“œ ์š”์ฒญ
    scope=profile

 

client_id : ์ธ์ฆ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธํ•œํ…Œ ํ• ๋‹นํ•œ ๊ณ ์œ  ์‹๋ณ„์ž

redirec_uri : ๋กœ๊ทธ์ธ ์„ฑ๊ณต์‹œ์— ์ด๋™ํ•  URI (์ธ๊ฐ€ ์ฝ”๋“œ ๋ฐ›์„๋•Œ ์“ฐ์ž„)

 

response_type : ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ œ๊ณต๋ฐ›๊ธธ ์›ํ•˜๋Š” ์‘๋‹ต ํƒ€์ž… ( code๊ฐ’ ํฌํ•จํ•ด์•ผ๋จ )

scope : ๋ฐ›๊ณ ์‹ถ์€ ์ •๋ณด ๋ชฉ๋ก

 

 

**์ฐธ๊ณ ๋กœ ์ธ๊ฐ€ ์ฝ”๋“œ๋Š”

์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ, ๊ถŒํ•œ ๋™์˜ ๋๋ƒ‡์„๋•Œ

ํด๋ผ์ด์–ธํŠธ(๋‚ด๊ฐ€ ๋งŒ๋“  ์•ฑ)๊ฐ€ ์ธ์ฆ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›๋Š” ์งง์€ ๋ฌธ์ž์—ด์ž„

GET http://localhost:8080/oauth/kakao/callback?code=abc123xyz

 

์ธ์ฆ ์„œ๋ฒ„๋Š” ๋ฐ”๋กœ access_token์„ ์ฃผ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ธ๊ฐ€ ์ฝ”๋“œ ๋จผ์ € ์คŒ.


 

๋ฐ์ดํ„ฐ ์ ‘๊ทผ์šฉ ๊ถŒํ•œ ๋ถ€์—ฌ

 

์ธ์ฆ ์„œ๋ฒ„์— ์š”์ฒญ์„ ์ฒ˜์Œ ๋ณด๋‚ผ ๋•Œ,

์‚ฌ์šฉ์žํ•œํ…Œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋ณด์—ฌ์ฃผ๊ณ  ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋™์˜๋ฅผ ์–ป์Œ (์ตœ์ดˆ 1ํšŒ๋งŒ)

์ดํ›„์—๋Š” ์ธ์ฆ ์„œ๋ฒ„์—์„œ ๋™์˜ ๋‚ด์šฉ ์ €์žฅํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฑ ๋กœ๊ทธ์ธ๋งŒ ๋ฐ”๋กœ ํ•จ.

 

๋กœ๊ทธ์ธ ์™„๋ฃŒ๋˜๋ฉด ๊ถŒํ•œ ๋ถ€์—ฌ ์„œ๋ฒ„๋Š” ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ๊ฒŒ

์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ์ˆ˜์‹ ํ•จ.

 

 

 

 

 

์ธ์ฆ ์ฝ”๋“œ ์ œ๊ณต

 

์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•˜๋ฉด, 

์ฒจ์— ์š”์ฒญ ๋ณด๋‚ผ๋•Œ ๋ณด๋ƒˆ๋–ค redirect_uri๋กœ ๋ฆฌ๋‹ค์ด๋ ‰์…˜๋˜๊ณ ,

์ด๋•Œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ์คŒ.

 

 

GET http://localhost:8080/myapp?code=a1s2f3g4

 

 

 

 

 

 

์—‘์„ธ์Šค ํ† ํฐ ์‘๋‹ต์ด๋ž€?

 

์œ„์™€ ๊ฐ™์ด ์ธ์ฆ ์ฝ”๋“œ ๋ฐ›์œผ๋ฉด, ์—‘์„ธ์Šค ํ† ํฐ์œผ๋กœ ๊ตํ™˜ํ•ด์•ผ๋จ.

์—‘์„ธ์Šค ํ† ํฐ = ๋กœ๊ทธ์ธ์„ธ์…˜์— ๋Œ€ํ•œ ์ž๊ฒฉ์„ ์ฆ๋ช…ํ•˜๋Š” ์‹๋ณ„ ์ฝ”๋“œ.

๋ณดํ†ต /token POST ์š”์ฒญ ๋ณด๋ƒ„

 

ex)

POST spring-authorization-server.example.com/token
{
	"client_id" : "66aasdf",
    "client_secret" : "aaabbbcc111",
    "redirect_uri" : "http://localhost:8080/myapp",
    "grant_type" : "authorization_code",
    "code" : "a1s2f3g4"
}

 

 

client_secret : OAuth ์„œ๋น„์Šค์— ๋“ฑ๋กํ•  ๋•Œ ์ œ๊ณต๋ฐ›๋Š” ๋น„๋ฐ€ํ‚ค

grant_type : ๊ถŒํ•œ ์œ ํ˜• ใ…‡ํ™•์ธํ•  ๋•Œ ์‚ฌ์šฉ.

๊ถŒํ•œ ์„œ๋ฒ„๋Š”, ์š”์ฒญ ๊ฐ’ ๊ธฐ๋ฐ˜์œผ๋กœ ์œ ํšจ์„ฑ ํ™•์ธํ•˜๊ณ 

์œ ํšจํ•˜๋‹ค๋ฉด ์—‘์„ธ์Šค ํ† ํฐ์œผ๋กœ ์‘๋‹ตํ•จ.

ex)

{
	"access_token" : "aassdf",
    "token_type" : "Bearer",
    "expires_in" : 3600,
    "scope" : "openid profile",
    ...
}

 

 

์ด ๋•Œ ์ œ๊ณต๋ฐ›์€ ์—‘์„ธ์Šค ํ† ํฐ์œผ๋กœ ๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ ์ •๋ณด ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ.

์ •๋ณด๊ฐ€ ํ•„์š”ํ• ๋•Œ๋งˆ๋‹ค APIํ˜ธ์ถœํ•ด์„œ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ณ 

๋ฆฌ์†Œ์Šค ์„œ๋ฒ„๋Š” ํ† ํฐ ์œ ํšจํ•œ์ง€ ํ™•์ธํ•˜๊ณ , ์‘๋‹ต.

 

์š”์ฒญ ex)

GET Spring-authorization-resource-server.example.com/userinfo
Header:Authorization: Bearer aassdf

 

 

(์ฐธ๊ณ ๋กœ ๋‚ด ์„œ๋น„์Šค์˜ ๋กœ๊ทธ์ธ ์ƒํƒœ๋Š” ๋”ฐ๋กœ ๊ด€๋ฆฌํ•จ

๋‚ด ์„œ๋ฒ„์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด ๋ณด๊ณ  JWT ๋ฐœ๊ธ‰ํ•˜๊ฑฐ๋‚˜ ์„ธ์…˜ ์ €์žฅํ•ด์„œ

์šฐ๋ฆฌ ์„œ๋น„์Šค ๋กœ๊ทธ์ธ ์ƒํƒœ ์œ ์ง€ํ•ด์•ผ๋จ)

 


 

์ •๋ฆฌํ•˜์ž๋ฉด

 

1. ์•ฑ -> ์ธ์ฆ์„œ๋ฒ„ : ์ธ๊ฐ€ ์ฝ”๋“œ ๋‹ฌ๋ผ๊ณ  GET ์š”์ฒญ ๋ณด๋ƒ„

2. ์ธ์ฆ์„œ๋ฒ„ -> ์‚ฌ์šฉ์ž : ๋™์˜ํ™”๋ฉด, ๋กœ๊ทธ์ธ ํ™”๋ฉด ๋ณด์—ฌ์ฃผ๊ณ  ๋™์˜ ์–ป๊ณ  ๋‚˜๋ฉด

3. ์ธ์ฆ์„œ๋ฒ„ -> ์•ฑ : ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ url๋กœ ์ธ๊ฐ€ ์ฝ”๋“œ ์คŒ

 

4. ์•ฑ -> ์ธ์ฆ์„œ๋ฒ„ : ๋ฐฉ๊ธˆ ๋ฐ›์€ ์ธ๊ฐ€ ์ฝ”๋“œ๋กœ, ์ด๋ฒˆ์—๋Š” ์—‘์„ธ์Šค ํ† ํฐ ๋‹ฌ๋ผ๊ณ  POST ์š”์ฒญ ๋ณด๋ƒ„

5. ์ธ์ฆ์„œ๋ฒ„ -> ์•ฑ : JSON ํ˜•ํƒœ๋กœ ์—‘์„ธ์Šค ํ† ํฐ ์คŒ

 

6. ์•ฑ -> ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„ : 5๋ฒˆ์—์„œ ๋ฐ›๋Š” ์—‘์„ธ์Šค ํ† ํฐ์œผ๋กœ

GET /user/me + Authorization Bearer (์—‘์„ธ์Šค ํ† ํฐ)

์ด๋ ‡๊ฒŒ GET ์š”์ฒญ ๋ณด๋ƒ„

7. ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„ -> ์•ฑ : ์‚ฌ์šฉ์ž ์ •๋ณด ์คŒ

(์ด ๋•Œ Authentication๊ฐ์ฒด์— ์ฃผ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, kakaoId, email, nickname๋“ฑ์„ ๋ฐ›๊ณ 

๊ทธ๊ฑธ ๋‚ด ์„œ๋น„์Šค์˜ ์œ ์ €๋ฅผ ์‹๋ณ„ํ•˜๊ณ , ํšŒ์›๊ฐ€์ž… ์‹œํ‚ด

ํ•ด๋‹น ์œ ์ €๋กœ Authentication๊ฐ์ฒด ๋งŒ๋“ค์–ด์„œ SecurityContextHolder์— ์ €์žฅ!)

 

 

Q. ์™œ ์ธ๊ฐ€ ์ฝ”๋“œ ๋‹ฌ๋ผ๊ณ  ํ• ๋• GET ์š”์ฒญ์ด๊ณ  ,  ์—‘์„ธ์Šค ํ† ํฐ ๋‹ฌ๋ผ๊ณ  ํ• ๋• POST ์š”์ฒญ์ž„?

 

A.

GET ์ธ๊ฐ€ ์ฝ”๋“œ ์š”์ฒญ์€, ์‚ฌ์šฉ์ž๋ฅผ ๋กœ๊ทธ์ธ, ๋™์˜ ํ™”๋ฉด์œผ๋กœ ๋ฆฌ๋””๋ ‰์…˜ ์‹œํ‚ค๋ ค๋Š”๊ฒŒ ๋ชฉ์ ์ž„

url๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ๋ธŒ๋ผ์šฐ์ € ์ด๋™์ด ๋˜๋‹ˆ๊นŒ.

 

POST ์—‘์„ธ์Šค ํ† ํฐ ์š”์ฒญ์€, ๋ฏผ๊ฐํ•œ ์ •๋ณด(clietn_secret๋“ฑ)๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ฃผ๊ณ ๋ฐ›๊ธฐ ์œ„ํ•ด POST ์š”์ฒญ ์“ฐ๋Š”๊ฑฐ์ž„

url์— ์š”์ฒญ๋˜๋ฉด ์•ˆ๋˜๋‹ˆ๊นŒ

 

๋ฐ˜์‘ํ˜•