Sign In With Apple
: ์๋ก์ด ID ์ ๊ณต ์
์ฒด์ ๋ํด ์์๋ณด์ญ์์ค.์๋ฌธ: https://auth0.com/blog/what-is-sign-in-with-apple-a-new-identity-provider/
Apple WWDC 2019์์ ๋ฐํ๋ ์๋ก์ด ID ์ ๊ณต ์
์ฒด์ธ Sign In With Apple
์ ๋ํด ์์๋ณด์ญ์์ค.
๋ธ๋ฃจ๋ ธ ํฌ๋ ์ค 2019-06-06!!
๋ชฉ์ฐจ
Sign In With Apple
์ ์ง์ํด์ผ ํฉ๋๊น?Sign In With Apple
๊ตฌํ์ด์ Auth0์ ๋ง์ถค์ ์์ ์ฐ๊ฒฐ ๋๋ถ์ ์ฑ์ ํน๋ณํ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ง ์๊ณ ๋ Sign In With Apple์ ๊ตฌํํ ์ ์์ต๋๋ค! Sign In With Apple์ ๊ตฌํํ์ญ์์ค.
TL;DR: Apple WWDC 2019์์ ๋ฐํ๋ Sign In With Apple
๊ธฐ๋ฅ์ ๋ํด ์์๋ณด์ญ์์ค. ์ด ์ธ์ฆ ์ต์
์ ๊ณง ๋ชจ๋ App Store ์์ฉ ํ๋ก๊ทธ๋จ์ ํ์๊ฐ ๋ ๊ฒ์ด๋ฉฐ, ์์ฉ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ์์๊ฒ ๋ช ๊ฐ์ง ๋ฌธ์ ์ ์ ์ ๊ธฐํ ์ ์์ต๋๋ค. ์น ๋ฐ ๋ค์ดํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฐ์ ๊ฑธ์ณ ํฅ์๋ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ ๋ฐ ์๋ฒฝํ ๋ก๊ทธ์ธ์ ํตํด Apple ์์ฝ ์์คํ
์ฌ์ฉ์์๊ฒ ๋ ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
Apple ๊ธฐ๋ฅ ๋ฐฉ๋ฌธ ํ์ด์ง ๋ชจํ ์ฌ์ง์ผ๋ก ๋ก๊ทธ์ธํ์ญ์์ค.
"Apple WWDC 2019์์ ๋ฐํ๋ ์๋ก์ด ID ์ ๊ณต ์
์ฒด ์ธ Sign In With Apple
์ ๋ํด ์์๋ณด์ญ์์ค."
์ฌํด WWDC์์ ์ ํ์ด ์ ํ๋ ค๊ณ ํ๋ ์ฃผ์ ๋ฉ์์ง ์ค ํ๋๋ ํ์ฌ๊ฐ ํ๋ผ์ด๋ฒ์๋ฅผ ์ผ๋ คํ๋ค๋ ๊ฒ์ ๋๋ค. ์ด ๋ฉ์์ง๋ฅผ ์ ์งํ๊ธฐ ์ํด ๋ค๋ฅธ ๋ ธ๋ ฅ๊ณผ ํจ๊ป, ์ํํธ์จ์ด ๊ณตํ์ ์์ ๋ถ์ฌ์ฅ ํฌ๋ ์ด๊ทธ ํ๋๋ฆฌ๊ธฐ๋ "Sign In With Apple" ๊ธฐ๋ฅ์ ๋์ ์์ดํฐ OS(13)์ ๋งฅ OS ์นดํ๋ฆฌ๋ ์ถ์๋ ์์ ์ผ๋ก ์ ๋ณด์์ต๋๋ค.
๊ทธ๊ฐ ์ธ๊ธํ ๊ฒ์ฒ๋ผ, ์์ ๊ณ์ ์ ์ฌ์ฉํ์ฌ ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ก๊ทธ์ธํ๋ฉด ์์ฉ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ์์ ์์ ๊ณต๊ธ์๊ฐ ์ถ์ ํ ์ ์์ต๋๋ค. ์ด ์ผ๋ฐ์ ์ธ ๊ดํ์ ์๊ฐ๋ ๊ฐ์ธ ์ ๋ณด ๋ณดํธ ๋ฌธ์ ๋ฅผ ์ ์ํ ํ Craig๋ ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ ์ ์ํ์ต๋๋ค. Apple์ ๋ก๊ทธ์ธํ์ญ์์ค.
ํฌ๋ ์ด๊ทธ (Craig)์ ๋ง์ ๋ฐ๋ฅด๋ฉด, ์ด ์๋ฃจ์ ์ "๊ฐ๋ฐ์๊ฐ ์์ ์ ์ฑ์ ๋ฐ๋ก ์๋ช ๋ฒํผ์ ๋ฃ์ ์ ์๋ ๊ฐ๋จํ API"๋ฅผ ๊ฐ๊ฒ ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ฌ์ฉ์๊ฐ ์ด ์์ด๋ ๊ณต๊ธ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ์ ๋ก๊ทธ์ธํ๋ ๊ฒฝ์ฐ Apple์ "์ฌ์ฉ์๊ฐ ๋ณ๋๋ก ์ ํํ์ง ์๋ ํ" ์ด๋ ํ ๊ฐ์ธ ์ ๋ณด๋ ๊ณต๊ฐํ์ง ์๊ณ ์ธ์ฆํฉ๋๋ค.
WWDC 2019 ๊ธฐ์กฐ ์ฐ์ค ์ค ์ด ๋ถ๋ถ์ ์ด์ ์ค ํ๋๋ ์ด ๊ธฐ๋ฅ์ ํตํด ์ฌ์ฉ์๋ ๋ค์ ์ค ํ๋๋ฅผ ์ํ ํ ์ ์์์ต๋๋ค.
๊ฐ์ธ ์ ๋ณด๋ฅผ ์ค์์ํ๋ ์ฌ์ฉ์์๊ฒ๋ ์ฒซ ๋ฒ์งธ ์ต์ ์ด ์ ํฉํ์ง ์์ต๋๋ค. ๊ฐ์ธ ์ด๋ฉ์ผ ์ฃผ์๊ฐ ์ฌ์ฉํ๋ ค๊ณ ํ๋ ์ฑ๊ณผ ๊ณต์ ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ฌํ ์ฌ์ฉ์์๊ฒ๋ ๋ ๋ฒ์งธ ์ต์ ์ด ๋งค์ฐ ๋งค๋ ฅ์ ์ ๋๋ค.
ํฌ๋ ์ด๊ทธ (Craig)๋ ์ฌ์ฉ์๊ฐ ์ ์ ๋ฉ์ผ ์ฃผ์๋ฅผ ์จ๊ธฐ๋ ค๊ณ ๊ฒฐ์ฌํ์ ๋ ์ ํ์ ๊ฐ ์ฑ๋ง๋ค ๊ณ ์ ํ๊ฒ ๋ฌด์์๋ก ์์ฑ ๋ ์ ์ ๋ฉ์ผ ์ฃผ์ ๋ง ๊ณต์ ํ ๊ฒ์ด๋ผ๊ณ ์ค๋ช ํ๋ค. ์ ํ๋ฆฌ์ผ์ด์ ๋น ์ด๋ฉ์ผ ์ฃผ์์ ๊ณ ์ ์ฑ์ ์๋ก์ด ๊ธฐ๋ฅ์์ ๊ฐ์ฅ ํฅ๋ฏธ๋ก์ด ๋ถ๋ถ ์ค ํ๋์ ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ํตํด ์ ํ์ ์ฌ์ฉ์๊ฐ ๋ช ๋ฒ์ ํด๋ฆญ๋ง์ผ๋ก ๋ ์ด์ ์ ๊ฒฝ ์ฐ์ง ์๋ ์ฑ์ โโ"์์๊ฑฐ"ํ๋๋ก ํ์ฉํ ๊ฒ์ ๋๋ค. ์ฑ์ด ๋ฌด์์๋ก ์์ฑํ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ์ ๊ฑฐํ๋ฉด ๋ฉ๋๋ค.
"Sign In With Apple์ ์ฌ์ฉ์๊ฐ ๊ฐ ์ฑ๋ง๋ค ๊ณ ์ ํ๊ฒ ์์ฑ ๋ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ๋ฌด์์๋ก ๊ณต์ ํ ์ ์๊ฒ ๋๋ฏ๋ก ์์ ์ฑ์ ์ ๊ฑฐํ๋ ๊ฒ์ ๋งค์ฐ ๊ฐํธํฉ๋๋ค."
Sign In With Apple
์ ์ง์ํด์ผ ํฉ๋๊น?Apple์ ๋ฐํ ์์ ์ ์ ์๋ฏ์ด Sign In With Apple ๊ธฐ๋ฅ์ ์ฑํํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ฌ์ค, ์ ํ์์ด ๊ธฐ๋ฅ์ ์ธ๊ธ :
"์ฌํด ํ๋ฐ๊ธฐ์ ์์ ์ ์ผ๋ก ์ด์ฉํ ์ ์์ ๋ ์ 3 ์ ๋ก๊ทธ์ธ์ ์ง์ํ๋ ์ฑ ์ฌ์ฉ์์๊ฒ๋ ์ต์ ์ด ํ์ํ ๊ฒ์ ๋๋ค."
์ฆ, ์ฑ ์คํ ์ด์ ์ฑ์ ๊ฒ์ํ๊ณ ๋ค๋ฅธ ์ 3 ์ ๋ก๊ทธ์ธ ์ต์ (์ : Facebook, Google ๋๋ Twitter)์ ์ง์ํ๋ ๊ฒฝ์ฐ ๊ณง ์ด ๊ธฐ๋ฅ์ ์ง์ํด์ผ ํฉ๋๋ค. ๋น๋ถ๊ฐ ์ ํ์ ์ฑ์์ ์์ด๋ดํฐํฐ ๊ณต๊ธ์๋ก์ ์ ํ์ ์ง์ํ ํ์๊ฐ ์๋ค. ๊ฐ์ ๋ฌธ์์์ "์ด ๊ธฐ๋ฅ์ ์์ง ๋ฒ ํ ํ ์คํธ ์ค"์ด๋ผ๊ณ ๋์ด โโ์์ผ๋ฉฐ ์์ง ๊ณต๊ฐ ์๋ฌด๊ฐ ๋ง๋ฃ๋ ๋ ์ง๋ ์์ต๋๋ค.
"์ ํ์ด ๋๋ถ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ํ์ ์๋ก์ด ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ์ง์ํ ๊ฒ์ ์๊ตฌํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ ๋๋ค."
์ด ๊ธฐ๋ฅ์ ๋ํ ์ง์์ ์์ฉ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ์์๊ฒ ๋ง์ ๋์์ด ๋ ์ ์์ต๋๋ค. ์ฑ ๋ฆฌํฉํฐ๋ง์ ์ฌ์ด ์์ ์ด ์๋๋๋ค. ํนํ ๋ฆฌํฉํ ๋ง์ ID ๊ด๋ฆฌ์ ๊ฐ์ ๋ฏผ๊ฐํ ๊ธฐ๋ฅ์ด ํฌํจ๋์ด์๋ ๊ฒฝ์ฐ ๋์ฑ ๊ทธ๋ ์ต๋๋ค.
์์ด๋ดํฐํฐ ํ๋ก๋ฐ์ด๋๋ฅผ ๋ ์์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ , ํ๋์ฉ ํตํฉํ๋ ํ์ฌ๋ ๋ ๋ค๋ฅธ ํ๋ก๋ฐ์ด๋์ ๋ํ ์ง์์ ์ถ๊ฐํด์ผ ํฉ๋๋ค. ์ด๋ ๋ ์ค์ํ ์ฝ๋ ๋ฐ ํตํฉ์ ์์ฑํ๋ ๊ฒ์ ์๋ฏธํ๋ฉฐ, ์ฌ๋ฌ ์ธ์ด๋ก ์์ฑํด์ผ ํ ๊ฒฝ์ฐ ์์ ๋ถํ๊ฐ ๊ธ๊ฒฉํ ์ปค์ง ์ ์์ต๋๋ค.
๋น์ ์ด ์ด๊ฒ์ด iOS ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ํ ๊ด์ฌ์ฌ ์ผ ๋ฟ์ด๋ผ๊ณ ์๊ฐํ ์๋ ์์ง๋ง, ๊ทธ๋ ๊ฒ ๊ฐ๋จํ์ง๋ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๊ด๋ จ iOS ์ฑ์ด์๋ ์น ์ ํ๋ฆฌ์ผ์ด์
์ด์๋ ๊ฒฝ์ฐ Sign In With Apple
๋ ์ง์ํด์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์ด ์ํฉ์ ์์ํด๋ณด์ญ์์ค. iOS ์ฌ์ฉ์๊ฐ ์น ๋ฒ์ ์ ์ฑ์ ์ฌ์ฉํ๊ธฐ๋ฅผ ์ํฉ๋๋ค. ๋ก๊ทธ์ธ ๋ฐฉ๋ฒ์ ๋ฌด์์
๋๊น? ๋ค๋ฅธ ๊ณ์ ์ ๋ง๋ค ์ ์๋ค๊ณ ๊ธฐ๋ํ ์๋ ์์ต๋๋ค.
๋ฐ๋ฉด์ Auth0 ๊ณผ ๊ฐ์ ID ๊ด๋ฆฌ ์์คํ ์ ์ฌ์ฉํ๋ฉด ์ด๋ฌํ ๋ถ๋ด์ ์ค์ผ ์ ์์ต๋๋ค. ์ ์ ๊ด๋ฆฌ ์์คํ ์ด ์๋ก์ด ์ ์ ์ ๊ณต ์ ์ฒด์ ๋ํ ์ง์์ ์ถ๊ฐํ๊ณ ๋๋ฉด ์ค์์น ์ต์ ์ ์ฌ์ฉํ์ฌ์ด ์ต์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ํ์ฅ ํ ์ ์์ต๋๋ค.
๋ค์ ์น์ ์์๋ ์น ์์ฉ ํ๋ก๊ทธ๋จ์ Sign In With Apple ๊ธฐ๋ฅ๊ณผ ํตํฉํ๋ ค๋ ์ฒซ ์๋ ์ค ํ๋๋ฅผ ๋ณผ ์ ์์ต๋๋ค. ๊ธฐ์ ๋จ๊ณ์ ์์ง ๊ด์ฌ์ด ์๋ค๋ฉด์ด ์น์ ์ ๊ฑด๋ ๋ฐ์ด๋ ์ข์ต๋๋ค.
Sign In With Apple
๊ตฌํ์ด ์๋ก์ด ์์ด๋ดํฐํฐ ํ๋ก๋ฐ์ด๋๋ ์ฌ์ ํ ๋ฒ ํ ํ
์คํธ ์ค์ด์ง๋ง , Node.js์ Express ์น ์ ํ๋ฆฌ์ผ์ด์
์ Sign In With Apple
๊ธฐ๋ฅ์ ํตํฉํ ์ํ์ ์ด๋ฏธ ํตํฉํ์ต๋๋ค.
์ด ์ ์์๋ ์ํ์ ์คํํ๊ธฐ ์ํด ์ํํด์ผ ํ ์์ ์ ํ์ตํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฌ๊ธฐ์ ์ค๋ช ํ๋ ๋จ๊ณ๋ ๋ฐ๋ชจ ์ฉ์ ๋๋ค. ์ฆ, ๋ค์ ์ฝ๋๋ ์ฐธ์กฐ ์ฉ์ด๋ฉฐ ํ๋ก๋์ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ฉด ์๋ฉ๋๋ค (๊ณต๊ธ์์ ํตํฉํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๊ณต์ ์ง์นจ์ผ๋ก ๊ฐ์ฃผํด์๋ ์ ๋จ).
Sign In With Apple
๋ฐฉ๋ฒ๋คํํ ์ปค๋ฎค๋ํฐ๋ฅผ ์ํด Apple์ Apple์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ์ง์ํ๋ ๊ณต๊ฐ ํ์ค์ ๊ณ ์ํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค. ๊ทธ๋ค์ ๊ณต์์ ์ผ๋ก์ด ํ์ค์ ์ฌ์ฉํ๊ณ ์๋ค๊ณ ๊ณต๊ฐ์ ์ผ๋ก ๋งํ์ง ์์ผ๋ฉฐ, ๊ณต์ ๋ฌธ์์๋ ์ธ๊ธ์ด ํ๋๋ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ค์ ์น์ ์์ ๋ณด๊ฒ ๋ ๊ฒ์ฒ๋ผ Apple์ OAuth 2.0 ๋ฐ OIDC (OpenID Connect) ํ์ค์ ์ผ๋ถ๋ฅผ ์ฌ์ฉ ํ๊ณ ์์ต๋๋ค.
์ฐธ๊ณ : Apple์ด ์ง๊ธ๊น์ง ํ์ค์ ์ ์ํ ์ ์ผํ ์ธ๊ธ์ WWDC 2019์์ "Sign In With Apple ์๊ฐ" ํ๋ ์ ํ ์ด์ ์ 11๋ถ(11:00)์ ๋๋ค. ์ด ๋ถ๋ถ์์ ์ฐ์ฌ๋ ๋ค์๊ณผ ๊ฐ์ด ๋งํฉ๋๋ค. "๊ธฐ์กด OAuth ์์คํ ๊ณผ ํตํฉ๋ ๊ฒฝ์ฐ
Sign In With Apple
์ ๋งค์ฐ ์ต์ํ ๊ฒ์ ๋๋ค."
๋ค์์ ๋ณด๊ฒ ๋ ๊ฒ์ ์ฌ์ฉ์๊ฐ ์์ฑํ๋ ค๊ณ ํ๋ ์์ฉ ํ๋ก๊ทธ๋จ์ด ์ธ์ฆ ์ฝ๋ ๋ถ์ฌ ํ๋ก ์ OIDC ํน์ง์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์๋ฅผ ์ธ์ฆํ๋ค๋ ๊ฒ์ ๋๋ค. ๋ฐ๋ผ์ ์ฌ์ฉ์๊ฐ ์ฑ์ ๋ก๊ทธ์ธํ๋ ค๊ณ ํ๋ฉด ๋ค์ ํ๋ก์ธ์ค๊ฐ ์ํ๋ฉ๋๋ค.
์คํ ๋ฒํธ ์ธ ๊ฐ์ง๊ฐ ์๋ฃ๋๋ฉด ์ฑ ์ ๋ฌํ๋ ID ํ ํฐ ํ๋ํ ๋ช ๊ฐ์ง (๊ทธ๋ฌ๋, ๋ฏผ๊ฐํ ์๋ฌด๊ฒ๋) ์ฌ์ฉ์์ ๋ํ ์ ๋ณด๋ฅผ ํ์ํฉ๋๋ค.
์ฐธ๊ณ : ํ์ฌ๋ก์๋ ์์์ ์ฌ์ฉ์ ์๋ณ์ (์ : ์ด๋ฉ์ผ ์ฃผ์)๋ณด๋ค ์๋ฏธ์๋ ๊ฒ์ ์ป๋ ๋ฐฉ๋ฒ์ ์ ์ ์์ต๋๋ค. ํจ๊ป ๋์ง๋ ๋ง
scopes
.
"์ด ์ข๊ฒ๋, ์ ํ์ OAuth์ OpenID Connect๋ฅผ ๊ณ ์ํ๋ฉด์ ์ ํ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ๊ตฌ์ถํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค."
์ ์๋ ๋จ๊ณ๋ฅผ ๋ฐ๋ฅด๋ ๋ฐ ๊ด์ฌ์ด ์๋ค๋ฉด ์ฃผ๋ก ๋ค์ ๋ ๊ฐ์ง๊ฐ ํ์ํฉ๋๋ค. ์ฌ์ฉํ ์ ์๋ ๋๋ฉ์ธ (์ : brunokrebs.com
)๊ณผ ์์ฑํ๋ ค๋ ์น ์์ฉ ํ๋ก๊ทธ๋จ์ ๊ฐ๋ฆฌ ํต๋๋ค. ์ฑ์ ์คํํ๊ณ ์ด ๋๋ฉ์ธ์ ๋์ ํ์ฌ ์๋ตํ๋ "์ค์ "์๋ฒ (์ธํฐ๋ท์ ์ก์ธ์คํ ์ ์๋ ์ค์ ์๋ฒ์ฒ๋ผ)๊ฐ ์์ต๋๋ค.
๊ฒ๋ค๊ฐ ์ด ์๋ฒ๋ TLS ์ธ์ฆ์ (Apple์ ๋ณด์๋์ง ์์ HTTP ์ฐ๊ฒฐ์ ํ์ฉํ์ง ์์)์ npm ๋ฐ Node.js (์น ์์ฉ ํ๋ก๊ทธ๋จ์ ์คํํ ์ ์๋๋ก)๋ก ๊ตฌ์ฑํด์ผ ํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก Email Relay Service๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด SPF (Sender Policy Framework) DNS TXT ๋ ์ฝ๋๋ก ๋๋ฉ์ธ์ ๊ตฌ์ฑํด์ผ ํฉ๋๋ค. Apple ์ค๋ช ์์ ํจ๊ป ๊ณต์ ๋ก๊ทธ์ธํ๋ฉด ์ด๋ป๊ฒ ์ป์ ์ ์๋์ง ์ค๋ช ๋์ด ์์ต๋๋ค.
์ฐธ๊ณ : ์ด ๋์งํธ ์ค์ (์ ๊ฐ์ ์ผ๋ถ ์์ต์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ฒ๋ผ ์ฌ์ด ๋ฐฉ๋ฒ์ ์ค์ ๊น์ง ์ป๋ ์ด๊ฒ ๊ณผ ์ด๊ฒ ), Freenom ๋ฐ ํ์ ์ํธํ๋ฅผ.
๊ณ์ํ๊ธฐ ์ ์ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑํ๋์ง ํ์ธํ์ญ์์ค.
์ฐ์ , ํ๋ซํผ์ ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ฑ๋กํ๋ ๋ฐ ์ฌ์ฉํ ์ ์๋ Apple ๊ฐ๋ฐ์ ๊ณ์ ์ด ํ์ํฉ๋๋ค. ์ ๊ฐ์ค๋ฝ๊ฒ๋ ์ด๋ฌํ ์ ํ์ ๊ณ์ ์ ์ ๋ฃ์ด๋ฉฐ iOS ๊ฐ๋ฐ์ ๋ํ ํ๋ก๊ทธ๋จ์ ์ฐธ์ฌํ์ง ์๋ ํ ๋ฌด๋ฃ ํ๊ฐํ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ฐ๋ฐ์ ๊ณ์ ์ ๋ก๊ทธ์ธํ๋ฉด "์ธ์ฆ์, ID ๋ฐ ํ๋กํ" ์น์ ์ผ๋ก ์ด๋ํ์ฌ ์ผ์ชฝ ๋ฉ๋ด์์ "์๋ณ์" ํ์ ์น์ ์ ์ ํํด์ผ ํฉ๋๋ค.
์ด ํ์ ์น์
์์ '์ฑ ID ๋ฑ๋ก ๋ฒํผ'์ ํด๋ฆญํ๊ณ ์๋ณ์ ์ ํ์ผ๋ก ์ฑ ID๋ฅผ ์ ํํ ๋ค์ '๊ณ์'์ ํด๋ฆญํฉ๋๋ค. ๊ทธ๋ ๊ฒ ํ ํ์๋ ์๋ก์ด App ID ( "Apple Experimentation์ผ๋ก ๋ก๊ทธ์ธ"๊ณผ ๊ฐ์ ๊ธฐ๋ฅ) ๋ฐ ๋ฒ๋ค ID์ ๋ํ ์ค๋ช
์ ์ ๊ณตํด์ผ ํฉ๋๋ค. ํ์์ ๊ฒฝ์ฐ, ์ญ ๋๋ฉ์ธ ์ด๋ฆ ์คํ์ผ ๋ฌธ์์ด (์ : com.brunokrebs.appid
)์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ์กฐ๊ธ ์๋๋ก ์คํฌ๋กคํ์ฌ "Sign In With Apple" ๊ธฐ๋ฅ์ ํ์ธํ์ญ์์ค. Apple์ด ์ ๊ณตํ๋ "ํธ์ง"๋ฒํผ์ ์ฌ์ฉํ ํ์๊ฐ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ ์กฐ๊ธ๋ง ๊ตฌ์ฑํ๋ฉด ๋ฉ๋๋ค.
์ด์ ๋ค๋ฅธ ์ต์ ์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก๋๊ณ "๊ณ์"์ ๋๋ฅด์ญ์์ค. ์ด ๋จ์ถ๋ฅผ ํด๋ฆญํ๋ฉด ๋ฐฉ๊ธ ์ฑ์ด ์ต์ ์ ๋ํ ์์ฝ ์ ๋ณด๊ฐ ํ์๋ฉ๋๋ค. ๋ชจ๋ ๊ฒ์ด ์ ๋๋ก ์๋ํ๋ฉด "Register"๋ฒํผ์ ๋๋ฌ ํ๋ก์ธ์ค๋ฅผ ์ข ๋ฃํ์ญ์์ค.
์ ์ ํ, Apple์ "์ธ์ฆ์, ์๋ณ์ ๋ฐ ํ๋กํ"ํ์ ์น์ ์ผ๋ก ๋ค์ ๋ฆฌ๋๋ ์ ํฉ๋๋ค. ์ด๋ฒ์๋ ์ ์ฑ ID๋ฅผ ๋์ดํฉ๋๋ค. ๋ค์์ ํ์ํ ๊ฒ์ Node.js ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ํ๋ด๋ ์๋น์ค ID๋ฅผ ๋ง๋๋ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ ์ค๋ณต ๋ ๋ ธ๋ ฅ์ฒ๋ผ ๋ณด์ผ์ง๋ ๋ชจ๋ฅด์ง๋ง ์ ํ์ ๊ฐ์ ๊ฒ์ ์ ๋ฆฌํ์ฌ ๋์ผํ ์ฑ ID๋ก ์ฌ๋ฌ ์๋น์ค ID๋ฅผ ์ค์ฒฉ ํ ์ ์์ต๋๋ค. ์ด๋ ์๋ก ๋ค๋ฅธ ์ฅ์น๋ฅผ ์ง์ํ๋ ์ฑ์ ๋ฒ์ ์ด ๋ค๋ฅผ ๋ ํจ์ฌ ๋ ์ ํฉํฉ๋๋ค.
๋ฐ๋ผ์ "์๋ณ์"ํค๋ ์์ ์๋ ๋ฅ๊ทผ ํ๋์ ์์ด์ฝ์ ํด๋ฆญํ์ญ์์ค. "์๋น์ค ID"๋ฅผ ์ ํํ๊ณ "๊ณ์"์ ํด๋ฆญํ์ญ์์ค. ๋ค์ ํ๋ฉด์์ ์ด์ ๊ณผ ๋์ผํ ํ๋ (์ค๋ช ๋ฐ ์๋ณ์)๋ฅผ ์ฑ์์ผํ๊ณ "Sign In With Apple"๊ธฐ๋ฅ์ ํ์ฑํํด์ผ ํฉ๋๋ค. ๋ ํ๋์ ๊ฒฝ์ฐ "Apple Web App์์ ๋ก๊ทธ์ธ"(์ค๋ช )๊ณผ ๊ฐ์ ๊ฐ์ ์ฌ์ฉํ ์ ์์ต๋๋ค com.brunokrebs.webapp.
๊ทธ ์ธ์๋ "Sign In With Apple" ๊ธฐ๋ฅ์ ํ์ธํ ํ์๋ ์์ ์๋ "๊ตฌ์ฑ"๋ฒํผ์ ํด๋ฆญํด์ผ ํฉ๋๋ค. ์ด ๋ฒํผ์ ํด๋ฆญํ๋ฉด Apple์ "์น ๋๋ฉ์ธ"์ ์ ์ํ๊ณ (์: brunokrebs.com
), "Return URL"(์:brunokrebs.com/callback
)์ ์ถ๊ฐํด์ผ ํ๋ ๋ํ ์์๋ฅผ ํ์ํฉ๋๋ค. ์ด ์ ๋ณด๋ฅผ ์
๋ ฅํ ํ "์ ์ฅ"๋ฒํผ์ ํด๋ฆญํ์ญ์์ค. ๊ทธ๋ฐ ๋ค์ "์๋น์ค ID ๋ฑ๋ก"ํ๋ฉด์ผ๋ก ๋์๊ฐ์ "๊ณ์"์ ํด๋ฆญํ๊ณ ๋ค์ ํ๋ฉด์์ "๋ฑ๋ก"์ ํด๋ฆญํ์ญ์์ค.
์๋น์ค ID๋ฅผ ๋ฑ๋กํ๋ฉด Apple์์ "์ธ์ฆ์, ์๋ณ์ ๋ฐ ํ๋กํ"ํ์ด์ง๋ก ๋ค์ ์ฐ๊ฒฐ๋ฉ๋๋ค. ๊ฑฐ๊ธฐ์ ์๋ก ์์ฑ ๋ ์๋น์ค ID๊ฐ ํ์๋๋ฉฐ ๋ง์ง๋ง ๊ตฌ์ฑ ๋จ๊ณ๋ฅผ ์ํํ๊ธฐ ์ํด ํด๋ฆญํด์ผ ํฉ๋๋ค (๋ถํํ๊ฒ๋์ด ๋จ๊ณ๋ ์๋น์ค๋ฅผ ๋ฑ๋กํด์ผ๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค).
ํด๋ฆญํ๋ฉด Apple์์ ์๋น์ค์ ์ธ๋ถ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค๋๋ค. ๊ฑฐ๊ธฐ์์ "Sign In With Apple"๊ธฐ๋ฅ ์์ ์๋ "๊ตฌ์ฑ"๋ฒํผ์ ๋๋ฌ์ผํฉ๋๋ค. ์ด๋ฒ์๋ ๊ทํ์ ๋๋ฉ์ธ ์์ "๋ค์ด๋ก๋"๋ฐ "ํ์ธ"์ด๋ผ๋ ๋ ๊ฐ์ ์๋ก์ด ๋จ์ถ๊ฐ ์์์ ์ ์ ์์ต๋๋ค.
"๋ค์ด๋ก๋"๋ฒํผ์ ํด๋ฆญํ๋ฉด Apple์์ ํ์ผ์ ๋ณด๋
๋๋ค apple-developer-domain-association.txt
. ์ด ํ์ผ์ ๊ณง ์ฌ์ฉํด์ผ ํ๋ฏ๋ก ์ฃผ๋ณ์ ๋ณด๊ดํ์ญ์์ค. ๋ํ ํ์ด์ง๋ฅผ ์ด์ด ๋์ญ์์ค. ์ ์ ํ์ "ํ์ธ"๋ฒํผ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
Apple ๊ฐ๋ฐ์ ๊ณ์ ์ ๊ตฌ์ฑํ ํ ์น ์์ฉ ํ๋ก๊ทธ๋จ ์ฝ๋ ์์
์ ์์ํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ ค๋ฉด ํฐ๋ฏธ๋์ ์ด๊ณ ์ผ๋ฐ์ ์ผ๋ก ํ๋ก์ ํธ๋ฅผ ์ ์ฅํ ์ ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ญ๋๋ค (์ด ๋๋ ํ ๋ฆฌ๋ฅผ ํธ์ถํ ์ ์์ apple-sign-in-sample
). ๊ทธ๋ฐ ๋ค์ ์ ๋๋ ํ ๋ฆฌ์์ npm ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๊ณ ๋ช ๊ฐ์ง ์ข
์์ฑ์ ์ค์นํ์ญ์์ค.
# start the npm project
npm init -y
# install its dependencies
npm i dotenv \
express \
express-session \
jsonwebtoken \
passport \
passport-oauth
๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ์ด๋ฌํ ์ข ์์ฑ์ด ํ์ํฉ๋๋ค.
dotenv
: ์ฝ๋ ์์ฒด์์ ๋ ์ ์ ์ง๋๋ ํ๊ฒฝ ๋ณ์๊ฐ ํ์ํฉ๋๋ค.express
: ํ๋ก์ ํธ๋ฅผ Express ์น ์์ฉ ํ๋ก๊ทธ๋จ์ผ๋ก ๋ง๋ค์ด์ผ ํฉ๋๋ค.express-session
: passport ์ฌ์ฉ์์ ์ธ์
์ ๊ด๋ฆฌํ๋ ค๋ฉด ์ด ํจํค์ง๊ฐ ํ์ํฉ๋๋ค.jsonwebtoken
: passport ๊ตฌ์ฑํ๋ ๋์ ํด๋ผ์ด์ธํธ ๋น๋ฐ๋ฒํธ๋ก ์๋ํ๋๋ก JWT๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.passport
:์ด ํจํค์ง๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ์ ์ฌ์ฉ์ ์ธ์ฆ์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.passport-oauth
:์ด passport Strategy๋ฅผ ์ฌ์ฉํ์ฌ Apple์ ID ์ ๊ณต ์
์ฒด์ ํตํฉํด์ผ ํฉ๋๋ค.
์ด ํจํค์ง๋ฅผ ์ค์นํ ํ, ํธ์ถํ app.js
์ ํ์ผ์ ์์ฑํ๊ณ ๋ค์ ์ฝ๋๋ฅผ ์ฝ์
ํ์ญ์์ค.const express = require("express");
const session = require("express-session");
const port = process.env.PORT || 3000;
const passport = require("passport");
const OAuth2Strategy = require("passport-oauth").OAuth2Strategy;
const fs = require("fs");
const jwt = require("jsonwebtoken");
const domainAssociation = fs.readFileSync(
"./apple-developer-domain-association.txt",
"utf8"
);
const appleStrategy = "apple";
const app = express();
app.use(
session({
secret: "secret",
saveUninitialized: false,
resave: false
})
);
app.use(passport.initialize());
app.use(passport.session());
passport.use(
"apple",
new OAuth2Strategy(
{
authorizationURL: "https://appleid.apple.com/auth/authorize",
tokenURL: "https://appleid.apple.com/auth/token",
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: process.env.CALLBACK,
state: Date.now() // bleh
},
(accessToken, refreshToken, payload, profile, done) => {
done(null, { profile, payload });
}
)
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
app.get("/.well-known/apple-developer-domain-association.txt", (req, res) => {
res.send(domainAssociation);
});
app.get("/auth/apple", passport.authenticate(appleStrategy));
app.get(
"/callback",
passport.authenticate(appleStrategy, {
successRedirect: "/",
failureRedirect: "/login"
})
);
app.get("/profile", (req, res) => {
res.send(
jwt.decode(req.session.passport.user.payload.id_token, { complete: true })
);
});
app.get("/", (req, res) => {
console.log("User", req.user);
res.send(JSON.stringify({ Hello: "World" }));
});
app.listen(port, () => {
console.log(`Apple Login POC listening on port ${port}!`);
});
์์ ์ฝ๋๋ฅผ ํ์ธํ๋ฉด apple-developer-domain-association.txt
ํ์ผ์ ๋ํ ์ฐธ์กฐ๊ฐ ์์์ ์ ์ ์์ต๋๋ค. ์ด ํ์ผ์ ์๋ฒ์์ ์คํํ๋ ๋์์ด ํ์ผ์ ์์ฉ ํ๋ก๊ทธ๋จ์์ ์ฌ์ฉํ ์ ์๊ฒ ํด์ผ ํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด Apple์์ ์ด์ ์น์
์์ ์ฌ์ฉํ ๋๋ฉ์ธ์ ์์ ์์ธ์ง ํ์ธํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์, Apple์์ ๋ค์ด๋ก๋ ํ ํ์ผ์ ํ๋ก์ ํธ ๋ฃจํธ๋ก ์ด๋ํ์ญ์์ค.
๊ทธ๋ฐ ๋ค์ ์ฝ๋๊ฐ ์๋ํ๋์ง ํ์ธํ๋ ค๋ฉด ๋ค์ ๋ช ๋ น์ ๋ก์ปฌ์์ ์คํํ์ญ์์ค.
export CLIENT_ID=test
export CLIENT_SECRET=test
export CALLBACK=test
npm start
์ฐธ๊ณ :test ํ์ฌ ํ๊ฒฝ ๋ณ์์ ๊ฐ์ ๋จ๊ฒจ ๋ ์ ์์ต๋๋ค. ๋์ค์ ์ด ๋ณ์๋ค์ ๊ตฌ์ฑํ ๊ฒ์ ๋๋ค.
๋ชจ๋ ๊ฒ์ด ์์๋๋ก ์๋ํ๋ฉด ๋ค์ ๋งํฌ์์ ๋๋ฉ์ธ ์ฐ๊ฒฐ ํ์ผ์ ๋ด์ฉ์ ๋ณผ ์ ์์ต๋๋ค http://localhost:3000/.well-known/apple-developer-domain-association.txt. ์ด ๊ฒฝ์ฐ ์ค์ ์๋ฒ์์ ์ฑ์ ์คํํ ์ค๋น๊ฐ ๋ ๊ฒ์ ๋๋ค.
์ด์ ํ๋ก์ ํธ ์ฝ๋๋ฅผ ์๋ฒ๋ก ์ฎ๊ฒจ ๋ก์ปฌ์์ ํ๋ ๊ฒ์ฒ๋ผ ์คํํฉ๋๋ค (์ฆ, ์ต์ข ํ๊ฒฝ ๋ณ์๋ฅผ ์ ๊ณต ํ ํ์๊ฐ ์์ต๋๋ค). ์ด๋ฅผ ๋ฌ์ฑํ๊ธฐ ์ํด ์ํ๋ ๊ฒ์ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ํ๋ด๊ธฐ๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ํ์ผ์ ์๋์ผ๋ก ์ด๋ํ ์ ์์ต๋๋ค (๋์ scp์ด๋ ๋น์ทํ ๋ฐฉ๋ฒ์ผ๋ก). ์ ์๋ ์๋ง ๋ ์ฌ์ธ ๊ฒ์ด๋ค.
์ด ํ๋ก์ ํธ๋ฅผ ์ค์ ์๋ฒ (Apple ๊ฐ๋ฐ์ ๊ณ์ ์์ ๊ตฌ์ฑํ ๋๋ฉ์ธ์ ๋์ ํ์ฌ ์๋ตํด์ผ ํจ)์์ ์คํํ ํ์๋ ์ด๋ ค ์๋ ํ์ด์ง๋ก ๋์๊ฐ์ "ํ์ธ"๋ฒํผ์ ํด๋ฆญ ํ ์ ์์ต๋๋ค. ๋ชจ๋ ๊ฒ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ด๋ฃจ์ด์ง๋ค๋ฉด Apple์ ๊ทํ๊ฐ ์ ๋ณด๋ฅผ ๊ฐ๊ณ ์๋ ๋๋ฉ์ธ์ ์์ ํ๊ณ ์์์ ํ์ธํ ์ ์์ต๋๋ค.
๊ทธ ์ธ์๋ Apple์์ ์ ๊ณตํ๋ ์ ์ ๋ฉ์ผ ๋ฆด๋ ์ด ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด "์ธ์ฆ์, ์๋ณ์ ๋ฐ ํ๋กํ" ์น์
์์ "์์ธํ"๋ฅผ ํด๋ฆญํ๊ณ "๊ตฌ์ฑ"์ ๋๋ฅด์ญ์์ค. ๋ค์ ํ์ด์ง์์ "๋๋ฉ์ธ ๋ฐ ๊ด๋ จ ์ด๋ฉ์ผ ์ฃผ์"์ ์๋ ์
๋ ฅ๋์ ๋๋ฉ์ธ (์ : brunokrebs.com
)์ ์ถ๊ฐํ๊ณ "๋ฑ๋ก"์ ๋๋ฅด์ญ์์ค. ๊ทธ๋ฐ ๋ค์ "๊ฐ๋ณ ์ด๋ฉ์ผ ์ฃผ์"์ ์ด๋ฉ์ผ ์ฃผ์ (์ : me@brunokrebs.com
)๋ฅผ ์ถ๊ฐํ๊ณ "๋ฑ๋ก"์ ๋๋ฅด์ญ์์ค.
์ฐธ๊ณ : ์ ์ ๋์์ด ์์ฑ์ ๊ตฌ์ฑํ๋๋ผ๋ ๋ฆด๋ ์ด ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด ๋ฌธ์๋ ๋ก๊ทธ์ธํ๋ ์ฌ์ฉ์๋ฅผ ์ํด ์์๋ก ์์ฑ ๋ ๊ณ ์ ํ ์ ์ ๋ฉ์ผ์ ์ป๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ ์ธ๊ธํ์ง ์์์ต๋๋ค. ๋ํ OpenID Connect ์ค์ฝํ๋ฅผ ์ฌ์ฉํ๋ฉด email(์ ์ด๋ ์์ง์) ์๋ํ์ง ์์ต๋๋ค.
Sign In With Apple
๊ตฌ์ฑ - ์ ์ ๋ฉ์ผ ์ค๊ณ ์๋น์คApple์ด ์ค๋ช ํ๋๋๋ก :
Apple์ ๊ฐ์ธ ์ ์ ๋ฉ์ผ ์ค๊ณ ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ ์ฌ์ฉ์์๊ฒ ์ฐ๋ฝํ๋ ค๋ฉด ์กฐ์ง์์ ํต์ ์ ์ฌ์ฉํ ๋๋ฉ์ธ๊ณผ ์ ์ ๋ฉ์ผ ์ฃผ์๋ฅผ ๋ฑ๋กํด์ผ ํฉ๋๋ค. ์ ์ ๋ฉ์ผ ์ฃผ์์ ๊ด๋ จ๋ ๋๋ฉ์ธ ๋ฐ ๋๋ฉ์ธ์ Sender Policy Framework ํ์ค์ ์ค์ํด์ผ ํ๋ฉฐ ์ฑ๊ณต์ ์ผ๋ก ๋ฑ๋ก๋๊ธฐ ์ ์ Apple์์ ํ์ธํด์ผ ํฉ๋๋ค.
์ด์ Apple์์ ๋๋ฉ์ธ์ ํ์ธํ์ผ๋ฏ๋ก ์ด ID ๊ณต๊ธ์๋ฅผ ์ฌ์ฉํ๋ ๋ฐ ํ์ํ ํ๊ฒฝ ๋ณ์๋ฅผ ์ ์ํ๋ ๊ฒ์ ๋ํด ๊ฑฑ์ ํ ์ ์์ต๋๋ค. ์ฒ์์๋ ๋ค์ ๋ณ์ ์ค ๋ ๊ฐ์ง๋ฅผ ์ฝ๊ฒ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
com.brunokrebs.webapp
)์ ์๋ณ์๋ก ์ฌ์ฉํ ๊ฐ์ ๊ฐ์ ธ์ต๋๋ค.brunokrebs.com/callback
)๋ก ์ ๋ฌํ ๊ฐ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์ด๋ฌํ ๋ณ์๋ฅผ ์ ์ํ ํ์ ๋ง์ง๋ง์ผ๋ก ๋จ์ CLIENT_SECRET
๋ณ์๊ฐ ์์ต๋๋ค. OAuth๋ฅผ ์ค์ํ๋ ๋๋ถ๋ถ์ ์์ด๋ ๊ณต๊ธ์์์ ์ด ๋งค๊ฐ ๋ณ์๋ ์ ์ ์
๋๋ค. ๊ทธ๋ฌ๋ ์ ํ์ ์ํด ์ด ๋น๋ฐ ํ์ ์ ํ๊ธฐ๋ก ๊ฒฐ์ ์๋ช
JSON ์น ํ ํฐ (JWT)๋ฅผ ์ฌ์ฉํ์ฌ exp
์์ฒญ ์ํ.์ด ํค๋ฅผ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๊ฐ๋ฐ์ ๋์๋ณด๋์ "์ธ์ฆ์, ์๋ณ์ ๋ฐ ํ๋กํ" ์น์ ์์ "ํค"๋ก ์ด๋ํด์ผ ํฉ๋๋ค. ์ฌ๊ธฐ์ ์ ํค๋ฅผ ์ถ๊ฐํ๋ ค๋ฉด ๋ฅ๊ทผ ํ๋์ ์์ด์ฝ์ ํด๋ฆญํด์ผ ํฉ๋๋ค. Apple์ด ์์์ ํ์ํ๋ฉด "Apple Key๋ก ๋ก๊ทธ์ธ"์ ์ฌ์ฉํ์ฌ "Key Name"ํ๋๋ฅผ ์ฑ์ฐ๊ณ "Apple๋ก ๋ก๊ทธ์ธ"์ต์ ์ ์ ํํ์ญ์์ค. ์ด ํ์ด์ง์์ "๊ตฌ์ฑ"์ ํด๋ฆญํ์ฌ "๊ธฐ๋ณธ ์์ฉ ํ๋ก๊ทธ๋จ ID ์ ํ"ํ๋๊ฐ ์์ฉ ํ๋ก๊ทธ๋จ ID๋ก ์ฑ์ ์ก๋์ง ํ์ธํ์ญ์์ค. ๊ทธ ์๋ฆฌ๋ฅผ ์งํค๋ฉด "์ ์ฅ"์ ๋๋ฅธ ๋ค์ "๊ณ์"์ ๋๋ฅธ ๋ค์ "๋ฑ๋ก"(์ธ ๊ฐ์ ๋ฒํผ, ์ธ ํ์ด์ง)์ ๋๋ฌ์ผ ํฉ๋๋ค.
Sign In With Apple
์ ์ํด ์๋ก์ด ๋น๊ณต๊ฐ ํค๋ฅผ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ๋ง์ง๋ง ํ๋ฉด์์ "๋ฑ๋ก"์ ํด๋ฆญํ๋ฉด Apple์์ ์ ํค๋ฅผ ๋ค์ด๋ก๋ํ ์ ์๋ ํ์ด์ง๋ก ๋ฆฌ๋๋ ์ ํฉ๋๋ค. ๋ฐ๋ผ์ ์ด ๋ฒํผ์ ํด๋ฆญํ๊ณ ๋ค์ด๋ก๋ ํ ํ ํ์ผ์ ํ๋ก์ ํธ ๋ฃจํธ๋ก ์ด๋ํ์ญ์์ค. ํ์ผ์ ์ด๋ํ๋ ๋์ ์์ ์ ์ฉ์ดํ๊ฒ ํ๋ ค๋ฉด ์ด๋ฆ์ ๋ฐ๊ฟ๋๋ค authkey.p8. Apple Developer Portal๋ก ๋์๊ฐ์ "์๋ฃ"๋ฅผ ํด๋ฆญํ๊ณ ํค ID๋ฅผ ์ ์ด ๋์ญ์์ค.
๊ทธ๋ฐ ๋ค์ ํ๋ก์ ํธ ๋ฃจํธ ๋ด๋ถ์์ ํธ์ถ๋๋ ์ ํ์ผ์ ๋ง๋ค๊ณ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
const jwt = require("jsonwebtoken");
const fs = require("fs");
const privateKey = fs.readFileSync("./authkey.p8");
const token = jwt.sign({}, privateKey, {
algorithm: "ES256",
expiresIn: "2 days",
audience: "https://appleid.apple.com",
issuer: "TEAM_ID",
subject: "com.brunokrebs.webapp",
keyid: "KEY_ID"
});
console.log("The token is:", token);
์ฐธ๊ณ :com.brunokrebs.webapp
์๋น์ค ID ๋ฐ TEAM_IDํ ID์ ์๋ณ์๋ก ๊ต์ฒดํด์ผ ํฉ๋๋ค. ์ด ๊ฐ์ ์ฐพ์ผ๋ ค๋ฉด ์ด ํ์ด์ง๋ฅผ ๋ฐฉ๋ฌธํ์ญ์์ค. ๋ํ KEY_ID๋ฅผ ์์ ์ธ๊ธํ ํค ID๋ก ๊ต์ฒดํด์ผ ํฉ๋๋ค.
์ด์ ์ด ์์ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ์ฌ ์ ํ ํฐ์ ์์ฑํ์ญ์์ค.
node generate-secret.js
์คํฌ๋ฆฝํธ๊ฐ ์ถ๋ ฅํ๋ ๊ฐ์ CLIENT_SECRET ํ๊ฒฝ ๋ณ์ ์์ ์ฌ์ฉํ ๊ฐ์ ๋๋ค. ๋ฐ๋ผ์ ์๋ฒ๋ก ๊ฐ์ ์คํ์ค์ธ ์น ์์ฉ ํ๋ก๊ทธ๋จ ์ธ์คํด์ค๋ฅผ ์ค์งํ๊ณ ๋ค์ ๋ช ๋ น์ ์คํํ์ญ์์ค.
# now you need to use the real values
export CLIENT_ID=com.brunokrebs.webapp
export CLIENT_SECRET=eyJ...KsA
export CALLBACK=https://brunokrebs.com/callback
npm start
์ฐธ๊ณ : ์ด๋ฒ์๋ ์ต์ข ๊ฐ์ผ๋ก ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํด์ผ ํฉ๋๋ค.
์ผ์ด ์์๋๋ก ์๋ํ๋ฉด ๋๋ฉ์ธ์์ ๋ค์ ์คํ๋๋ ์ฑ์ ๋ค์ ๋ณผ ์ ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ /auth/.apple
์ด ๋๋ฉ์ธ์์ ๊ฒฝ๋ก๋ฅผ ์์ฒญํ๋ฉด ์์ฉ ํ๋ก๊ทธ๋จ์ ๋ก๊ทธ์ธํ ์ ์๋๋ก ์์ฉ ํ๋ก๊ทธ๋จ์ด Sign In With Apple ํ์ด์ง๋ก ๋ฆฌ๋๋ ์
๋ฉ๋๋ค.
์ด ํ์ด์ง์์ ์ ํจํ ์๊ฒฉ ์ฆ๋ช ์ ์ฌ์ฉํ๋ฉด Apple์์ ๋ค์ค ์ธ์ฆ ํ๋ก์ธ์ค๊ฐ ๋๋ ํ ์ฑ์ ๋ก๊ทธ์ธํฉ๋๋ค.
๋ด์ฉ์ ์์ง ์ด๊ธฐ ๋จ๊ณ์ด์ง๋ง ์ด ํญ๋ชฉ๊ณผ ์์์ ์ค๋ช ํ ๋จ๊ณ์ ๋ํ ์์ธํ ๋ด์ฉ์ Apple ์์์ ๋ก๊ทธ์ธ ์ค๋ช ์๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
Apple์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ๋ํด ์์์ผ ํ ๊ฒ์ด ๋ง์ต๋๋ค. ๋ฐํ ์ดํ, Auth0์ ์ฌ๋ฌ ํ์ด ์ ์ฒด์ ์ธ ํจ์๋ฅผ ์ดํดํ๊ธฐ ์ํด ๋ ธ๋ ฅํ์ผ๋ฉฐ, Apple์ ์ฌ์ฉ์ ๋ฐ ์ฑ ๊ฐ๋ฐ์์๊ฒ ์ด๊ฒ์ด ์ด๋ป๊ฒ ์ํฅ์ ๋ฏธ์น๋์ง์ ๋ํด ๊ณ์ ์๋ ค์ค ๊ฒ์ ๋๋ค. ๋์์, ์ฐ๋ฆฌ๋ Auth0์ด ์ด๋ป๊ฒ Apple์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ๊ฐ๋ฅํ ํ ์ฝ๊ณ ๊ฐ๋ ฅํ๊ฒ ๊ตฌํํ ์ ์๋์ง์ ๋ํ ๊ฒ์ ์ง์ํ๊ณ ๊ณต์ ํ๋ ์๋ฅผ ์ ์ํ ๊ฒ ์ ๋๋ค.
์ด ๊ธฐ๋ฅ์ ๋ํด ๋ฌธ์ ์ฌํญ์ด ์์ผ์๋ฉด ์ด ๊ฒ์๋ฌผ์ ํ๋จ์ ์๋ ์๊ฒฌ๋์ ๋ฌธ์ํ์ญ์์ค!
๋ธ๋ฃจ๋ ธ ํฌ๋ ์ค
R & D ์ฝํ ์ธ ์ค๊ณ์
ํ์ฅ์ฑ์ด ๋ฐ์ด๋๊ณ ๋ณต์๋ ฅ์ด ๋ฐ์ด๋ ์์ฉ ํ๋ก๊ทธ๋จ ๊ฐ๋ฐ์ ์ด์ ์ ์ ๋๋ค. ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์๋ถํฐ ๋ง์ดํฌ๋ก์๋น์ค (Kubernetes, Docker ๋ฑ), ํ๋ก ํธ ์๋์ ์ด๋ฅด๊ธฐ๊น์ง ๋ชจ๋ ๊ฒ์ ์ข์ํฉ๋๋ค. ๋๋ "๋จ์ํ"์ฑ์ด ์ผ๋ง๋ ๋ณต์กํ ์ง ์ ํ ์์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ์กฐ๊ฐ์ด ํจ๊ป ์๋ํ์ฌ ์ต์ข ์ฌ์ฉ์์๊ฒ ๋น ๋ฅด๊ณ ์ฆ๊ฑฐ์ด ๊ฒฝํ์ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์๊ฐํ๋ ๊ฒ์ด ๋๋๊ฒ ๋๊ปด์ง๋๋ค.