๐Ÿ” [Flutter] Apple ๋กœ๊ทธ์ธ A to Z: ๋กœ๊ทธ์ธ, ์ธ์ฆ, ๊ทธ๋ฆฌ๊ณ  ํƒˆํ‡ด ์ฒ˜๋ฆฌ

Tygerยท2025๋…„ 2์›” 8์ผ
2

Flutter

๋ชฉ๋ก ๋ณด๊ธฐ
65/65
post-thumbnail

๐Ÿ” Apple ๋กœ๊ทธ์ธ A to Z: ๋กœ๊ทธ์ธ, ์ธ์ฆ, ๊ทธ๋ฆฌ๊ณ  ํƒˆํ‡ด ์ฒ˜๋ฆฌ

App Review Guidelines - Apple Developer
Sign in With Apple Overview
Revoke tokens | Apple Developer
Sign in with Apple - Human Interface Guidelines

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Flutter์—์„œ Apple ๋กœ๊ทธ์ธ์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ์ž์„ธํžˆ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

iOS ์•ฑ์„ ๋ฐฐํฌํ•  ๋•Œ, ๋กœ๊ทธ์ธ ๋ฐฉ์‹์œผ๋กœ ์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์ œ๊ณตํ•˜๊ฒŒ ๋˜๋ฉด ๋ฌด์กฐ๊ฑด Apple ๋กœ๊ทธ์ธ์„ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค. ์• ํ”Œ์˜ ์ •์ฑ…์ด๋‹ค.

์ˆ˜๋งŽ์€ ์•ฑ์„ ๋ฐฐํฌ ํ•ด๋ดค์ง€๋งŒ ์—ฌ์ „ํžˆ ๊ฐ€์žฅ ์–ต์ง€์Šค๋Ÿฌ์šด ์ •์ฑ…์ด๋ผ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ Apple Login ์˜๋ฌดํ™”๋‹ค..

๊ฒฝํ—˜์ƒ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐํฌํ•œ ์„œ๋น„์Šค๋“ค์˜ ์†Œ์…œ ๋กœ๊ทธ์ธ ๋น„์œจ์„ ๋ณด๋ฉด ๊ตญ๋‚ด๋Š” ๊ฑฐ์˜ ์นด์นด์˜ค๊ณ , ๊ธ€๋กœ๋ฒŒ์—์„œ๋Š” ๋‹จ์—ฐ ๊ตฌ๊ธ€์ด ์••๋„์ ์œผ๋กœ ๋น„์ค‘์ด ๋†’์•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋กœ๊ทธ์ธ ๊ฐœ๋ฐœ์‹œ ์• ํ”Œ ๋กœ๊ทธ์ธ์€ ๋งค์šฐ ๊ท€์ฐฎ์€ ์ž‘์—…์ผ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

ํ•˜์ง€๋งŒ ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด์„œ๋Š” ๊ฐœ๋ฐœ์ž๋กœ์„œ ์ •์ฑ…๋„ ์ง€์ผœ์•ผํ•˜๋‹ˆ Apple Login์„ ์‚ฌ์šฉํ•œ ๋กœ๊ทธ์ธ๊ณผ ์ธ์ฆ ์ ˆ์ฐจ ๋ฐ ํƒˆํ‡ด์‹œ ๊ฐ€์ด๋“œ๋ผ์ธ์— ๋”ฐ๋ฅธ ์—ฐ๋™ ํ•ด์ œ ์ ˆ์ฐจ๊นŒ์ง€ ์ •๋ฆฌํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

*์†Œ์…œ ๋กœ๊ทธ์ธ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, Apple ๋กœ๊ทธ์ธ์„ ์˜๋ฌด๋กœ ์ œ๊ณตํ•  ํ•„์š”๋Š” ์—†์Œ.

Understanding Apple Login Process

Apple ๋กœ๊ทธ์ธ ์ง„ํ–‰ ์ „ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ์ค€๋น„๋ฌผ์ด ํ•˜๋‚˜ ์žˆ๋‹ค. ๋ฐ”๋กœ Apple Developer Program ๋ฉค๋ฒ„์‹ญ ๊ณ„์ •์ด ํ•„์š”ํ•˜๋‹ค. ์ฆ‰ ์• ํ”Œ ๊ฐœ๋ฐœ์ž ๊ณ„์ •์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

๋งŒ์ผ ๊ฐœ๋ฐœ์ž ๊ณ„์ •์ด ์—†๋Š” ์ƒํƒœ๋ผ๋ฉด, ์ง„ํ–‰์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

์ง€์†์ ์œผ๋กœ iOS๋‚˜ Apple ๊ด€๋ จ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•  ์˜ˆ์ •์ด๋ผ๋ฉด ๋‹น์—ฐํžˆ ๋ฉค๋ฒ„์‹ญ ๊ตฌ๋…์ด ํ•„์š” ํ•˜๊ฒ ์ง€๋งŒ, ๋‹จ์ˆœ ํ•™์Šต์šฉ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋‹น์žฅ์˜ ๋ฉค๋ฒ„์‹ญ ๊ตฌ๋…์„ ์ถ”์ฒœํ•˜์ง€๋Š” ์•Š๊ณ  ํ•„์š”ํ•  ๋•Œ์— ๊ตฌ๋…์„ ํ•ด์„œ ์‚ฌ์šฉํ•ด ๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœ๋“œ๋ฆฐ๋‹ค. ๋งค๋…„ 129,000์›์„ ์ง€๋ถˆํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ์ฝ” ์ ์€ ๋ˆ์€ ์•„๋‹ˆ๋ฉฐ, ์ค‘๊ฐ„์— ๊ตฌ๋…์„ ์ค‘๋‹จํ•˜๊ฒŒ ๋˜๋ฉด ๋ฐฐํฌ๋œ ์•ฑ์€ ๋ชจ๋‘ ์ทจ์†Œ๋œ๋‹ค.

๋ณธ๊ฒฉ์ ์œผ๋กœ Apple ๋กœ๊ทธ์ธ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์•ž์„œ ํ•„์š”ํ•œ ์ ˆ์ฐจ๋“ค์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

๋จผ์ € ๊ฐ์ž์˜ ์ธ์ฆ, ๋ฐฑ์—”๋“œ, Serverless ๋“ฑ์˜ ํ™˜๊ฒฝ๋“ค์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์„ค์ • ๋ฐฉ๋ฒ• ๋ฐ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๋„ ์ผ๋ถ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋Š”๋ฐ ์ตœ๋Œ€ํ•œ ๋ชจ๋“  ๊ฒฝ์šฐ์— ๋Œ€ํ•ด์„œ ๋‹ค๋ค„๋ณผ ์˜ˆ์ •์ด๋‹ค.

์ฐธ๊ณ ๋กœ Firebase๋‚˜ ๋ฐฑ์—”๋“œ ์—†์ด๋„ Apple Login์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•˜๋‹ค.

Apple ๋กœ๊ทธ์ธ์€ OAuth 2.0 ๊ธฐ๋ฐ˜์˜ ์ธ์ฆ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. iOS, Mac OS, Web ๋“ฑ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , Android ๋˜ํ•œ ์ œํ•œ์ ์œผ๋กœ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์•„๋ž˜์—์„œ ์ž์„ธํžˆ ๋‹ค๋ค„๋ณด๊ฒ ์ง€๋งŒ Apple ๋กœ๊ทธ์ธ์‹œ์— ๋ฐ˜๋“œ์‹œ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„ ์ค‘์— ํ•˜๋‚˜๊ฐ€ Private Relay Email, ์‚ฌ์šฉ์ž ์ •๋ณด ๋ฐ ํ† ํฐ ๋ฌดํšจํ™”์— ๊ด€ํ•œ ๋‚ด์šฉ ์ด๋‹ค.
์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ ์ด๋ฉ”์ผ์„ ๊ณต์œ ํ•˜๊ธฐ๋ฅผ ์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์‹ค์ œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋Š” ํ™•์ธํ•  ๋ฐฉ๋ฒ•์ด ์—†๊ณ , ์‚ฌ์šฉ์ž ์ •๋ณด์— ๋Œ€ํ•œ ์ œ๊ณต๋„ ์ตœ์ดˆ ๋กœ๊ทธ์ธ์‹œ์—๋งŒ ์ œ๊ณต๋˜๊ณ  ์ด ํ›„ ๋กœ๊ทธ์ธ์‹œ์—๋Š” NULL์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ถ€๋ถ„์„ ๊ณ ๋ คํ•ด์„œ ์„ค๊ณ„ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

ํ† ํฐ ๋ฌดํšจํ™”๋Š” Apple์˜ ์ •์ฑ…์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•„์ˆ˜๋กœ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

App Store Review Guidelines - 5.1.1 (v) Sign in with Apple
Apps that use Sign in with Apple must also support account deletion initiated from within the app.

Apple Login ์ ˆ์ฐจ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์ง„ํ–‰ํ•ด ์ฃผ๋ฉด๋œ๋‹ค.

1. Apple ๋กœ๊ทธ์ธ ํ‘œ์‹œ
2. ์ธ์ฆ ๋ฐ ID ํ† ํฐ ๋ฐœ๊ธ‰
3. Identity Token ๊ฒ€์ฆ
4. ์‚ฌ์šฉ์ž ์ •๋ณด ์ œ๊ณต
5. ํšŒ์› ํƒˆํ‡ด์‹œ Apple ๊ณ„์ • ์—ฐ๊ฒฐ ํ•ด์ œ

๊ฐ ๋‹จ๊ณ„๋ณ„ ๋ฐฉ๋ฒ• ๋ฐ ์„ค๋ช…์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ž˜์—์„œ ์ž์„ธํžˆ ๋‹ค๋ค„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

Configuring Apple Sign-In

Apple ๋กœ๊ทธ์ธ์„ ์œ„ํ•œ ์‚ฌ์ „ ์„ค์ •์„ ์ง„ํ–‰ํ•ด์ฃผ์ž.

Apple Developer > Certificates, Identifiers & Profiles์— ์ ‘์†ํ•˜๋„๋ก ํ•˜์ž.

๊ฐœ๋ฐœ์ž ๊ณ„์ •๊ณผ ๊ด€๋ จ๋œ ๊ธฐ๋Šฅ์€ Apple Developer์—์„œ ์ œ๊ณตํ•˜๊ณ  ์žˆ๊ณ , ์•ฑ๊ณผ ๊ด€๋ จ๋œ ๊ธฐ๋Šฅ์€ Store Connect ์—์„œ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

๋””๋ฒจ๋กœํผ์—์„œ๋Š” ์•ฑ์˜ ์‹๋ณ„์ž์— Sign in with Apple ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ํ‚ค๋ฅผ ๋“ฑ๋กํ•˜๋Š” ์ ˆ์ฐจ๋ฅผ ์ง„ํ–‰ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

๋จผ์ € ์‹๋ณ„์ž๋ฅผ ์•„์ง ๋“ฑ๋กํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋ผ๋ฉด Identifiers ํƒญ์œผ๋กœ ์ด๋™ํ•ด์„œ ์ถ”๊ฐ€๋ฅผ ํ•ด์ฃผ์‹œ๋ฉด ๋œ๋‹ค.

Apple Developer์— ์ฒ˜์Œ ๋ฐฉ๋ฌธํ•˜์‹  ๋ถ„๋“ค๋„ ๊ณ„์‹ค ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ตœ๋Œ€ํ•œ ์ž์„ธํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค. ๊ธฐ์กด ์‹๋ณ„์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ถ„๋“ค์€ ์•„๋ž˜์— "Sign in with Apple" ํ™œ์„ฑํ™” ๋‹จ๊ณ„๋ถ€ํ„ฐ ์ง„ํ–‰ํ•˜์‹œ๋ฉด ๋œ๋‹ค.

์‹๋ณ„์ž๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์‹๋ณ„์ž๊ฐ€ ์žˆ๋Š”๋ฐ, ์•ฑ๋งŒ ํƒ€๊ฒŸํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— App IDs๋กœ ์ง„ํ–‰์„ ํ•˜์ž.

App๊ณผ App Clip ๋‘ ๊ฐ€์ง€๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด App์€ ์ผ๋ฐ˜์ ์œผ๋กœ App Store๋ฅผ ํ†ตํ•ด์„œ ์ œ๊ณตํ•˜๋Š” ์™„์ „ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๊ณ  App Clip์€ ์‚ฌ์šฉ์ž๊ฐ€ App Store์—์„œ ์ „์ฒด ์•ฑ์„ ์„ค์น˜ํ•˜์ง€ ์•Š์•„๋„ ํŠน์ • ๊ธฐ๋Šฅ์„ ๋น ๋ฅด๊ฒŒ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ๊ฒฝ๋Ÿ‰ํ™”๋œ ๋ฏธ๋‹ˆ ์•ฑ์ด๋ผ๊ณ  ๋ณด์‹œ๋ฉด ๋œ๋‹ค.
๊ธฐํšŒ๊ฐ€ ๋œ๋‹ค๋ฉด App Clip์— ๋Œ€ํ•ด์„œ ์ถ”ํ›„์— ๋‹ค๋ค„๋ด๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

App ํƒ€์ž…์„ ์„ ํƒํ•ด์ฃผ๋„๋ก ํ•˜์ž.

Bundle ID๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ๋ฉด ๋˜๋Š”๋ฐ, Bundle ID๋Š” ํ”„๋กœ์ ํŠธ์˜ XCode๋ฅผ ์—ด๋ฉด Bundle Identifier์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์ผ ๊ฐœ๋ฐœ์ž ๊ณ„์ •์— ์—ฌ๋Ÿฌ ์•ฑ์„ ๋ฐฐํฌํ•  ๊ณ„ํš์ด๋ผ๋ฉด Description ํ•„๋“œ์— ํ™•์‹คํ•œ ์ •๋ณด๋ฅผ ๊ธฐ์ž…ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.
์—ฌ๋Ÿฌ ์•ฑ์„ ๋ฐฐํฌํ•˜๊ฒŒ ๋˜๋”๋ผ๋„ ๊ฐœ๋ฐœ์ž ๊ณ„์ •์ด ํ•œ ๊ฐœ๋ผ๋ฉด ๋ชจ๋“  ์‹๋ณ„์ž๊ฐ€ ํ•ด๋‹น ํƒญ์—์„œ ๊ด€๋ฆฌ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์‹๋ณ„์ž ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด์„œ ์ ์ ˆํ•œ ๋„ค์ด๋ฐ์„ ๋„ฃ์–ด์•ผ ๊ด€๋ฆฌ๊ฐ€ ์ˆ˜์›”ํ•ด ์ง„๋‹ค.
์ด์ „์— ๋‹ค๋ฅธ ์‹๋ณ„์ž๋ฅผ ์‚ญ์ œํ•˜๋Š” ๋ฐ”๋žŒ์— ๊ณคํ˜น์„ ์น˜๋ค˜๋˜ ๊ฒฝํ—˜์ด ์žˆ์—ˆ๋‹ค...

๋‹จ ํ•˜๋‚˜์˜ ์•ฑ๋งŒ ๋ฐฐํฌํ•  ๊ฒฝ์šฐ๋ผ๋ฉด ๊ทธ๋ƒฅ ํ”„๋กœ์ ํŠธ๋ช…์„ ๋„ฃ์–ด์ฃผ๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ด๋‹ค.

์‹๋ณ„์ž์— Sign in with Apple ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™” ํ•ด์ฃผ์ž !

๊ธฐ์กด ์‹๋ณ„์ž๋ฅผ ์‚ฌ์šฉํ•˜์‹œ๋Š” ๋ถ„๋“ค์€ ์‹๋ณ„์ž๋ฅผ ํƒญํ•˜๋ฉด ํŽธ์ง‘์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Capabilities ํƒญ์—์„œ ์•„๋ž˜๋กœ ์Šคํฌ๋กคํ•˜์—ฌ Sign in with Apple์„ ์„ ํƒํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

์ด์ œ Apple ๋กœ๊ทธ์ธ์ด ํ™œ์„ฑํ™” ๋œ๊ฒƒ์ด๋‹ค.


(Optional) Edit Sign in with Apple

Edit ๋ฒ„ํŠผ์ด ๋ณด์ด๋Š”๋ฐ, Edit๊ณผ ๊ด€๋ จ๋˜์„œ๋Š” ํ•„์ˆ˜ ํ•ญ๋ชฉ์€ ์•„๋‹ˆ๋‹ˆ ํ•„์š”์— ๋”ฐ๋ผ ์ ˆ์ฐจ๋ฅผ ์ง„ํ–‰ํ•˜์‹œ๋ฉด ๋œ๋‹ค.

Sign in with Apple: App ID Configuration

App ID์— ๊ด€๋ จ๋œ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ์˜์—ญ์œผ๋กœ, ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ์—์„œ ์ธ์ฆ ์ •๋ณด๋ฅผ ๊ณต์œ ํ•˜๊ณ ์ž ํ•  ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Primary App ID๋ž€ ์—ฌ๋Ÿฌ ํ”Œ๋žซํผ ๊ฐ„์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ์•ฑ ๊ทธ๋ฃน์˜ ์ฃผ์š” ID ์—ญํ• ์„ ํ•œ๋‹ค.
์‚ฌ์šฉ์ž๊ฐ€ ํ•œ ๋ฒˆ ๋™์˜ํ•˜๋ฉด, ๊ทธ๋ฃน ๋‚ด ๋ชจ๋“  ์•ฑ์—์„œ Sign in with Apple ์ธ์ฆ ์ •๋ณด๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ดํ•ด๊ฐ€ ์ž˜ ์•ˆ ๋˜์‹œ๋Š” ๋ถ„๋“ค์€ iOS ๊ฐœ๋ฐœ ์‹œ ์‚ฌ์šฉํ•˜๋Š” App Groups์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์‹œ๋ฉด ๊ธˆ๋ฐฉ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.
App Group์€ ์—ฌ๋Ÿฌ ์•ฑ ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ, Primary App ID๋Š” ์ธ์ฆ ์ •๋ณด๋ฅผ ๊ณต์œ ํ•œ๋‹ค๋Š” ์ ์—์„œ ์œ ์‚ฌํ•˜๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ์„ ํƒ๋œ ์˜ต์…˜์€ ํ˜„์žฌ ๋“ฑ๋ก ์ค‘์ธ App ID๋ฅผ ์ƒˆ๋กœ์šด Primary App ID๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
๋งŒ์•ฝ "Group with an existing ..." ์˜ต์…˜์„ ์„ ํƒํ•˜๋ฉด, ๊ธฐ์กด์— ๋“ฑ๋ก๋œ Primary App ID์— ๊ทธ๋ฃนํ™”๋˜์–ด ๋™์ผํ•œ ์ธ์ฆ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Server-to-Server Notification Endpoint

ํ•ด๋‹น ์„น์…˜์€ ๋ฐฑ์—”๋“œ ํ™˜๊ฒฝ์ด๋‚˜ Firebase Authentication ๋“ฑ์˜ ์ธ์ฆ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

Apple์ด ์•ฑ์—์„œ ์ค‘์š”ํ•œ ๊ณ„์ • ๊ด€๋ จ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฐ์ง€ํ•˜๋ฉด ํ•ด๋‹น URL๋กœ ์•Œ๋ฆผ์„ ๋ณด๋‚ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ธ๋ฐ, ๋“ฑ๋กํ•œ URL์€ Apple์ด ์„œ๋ฒ„ ์š”์ฒญ์„ ์ „์†กํ•  ์›นํ›…(Webhook)์˜ ์—”๋“œํฌ์ธํŠธ ์—ญํ• ์„ ํ•˜๊ฒŒ ๋œ๋‹ค.

์•Œ๋ฆผ์ด ๋ฐœ์ƒํ•˜๋Š” ์ฃผ์š” ์ด๋ฒคํŠธ๋กœ๋Š” Apple ID์™€ ์•ฑ์˜ ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•œ ๊ฒฝ์šฐ(Revoke), Apple ID๊ฐ€ ์‚ญ์ œ๋œ ๊ฒฝ์šฐ, Private Relay Email์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ์ด๋‹ค.

์„ค์ • URL์€ ๋ฐ˜๋“œ์‹œ HTTPS๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉฐ, TLS 1.2 ์ด์ƒ์„ ์ง€์›ํ•ด์•ผ ํ•œ๋‹ค.
์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.


๋งˆ์ง€๋ง‰์œผ๋กœ ์ž…๋ ฅํ•œ ์ •๋ณด๋ฅผ ํ™•์ธ ํ›„ ์ƒ์„ฑํ•ด์ฃผ๋ฉด ์‹๋ณ„์ž๊ฐ€ ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Flavors ๋“ฑ์˜ ๋นŒ๋“œ ๋ณ€ํ˜•์„ ๊ตฌ์ถ•ํ•œ ํ™˜๊ฒฝ์ด๋ผ๋ฉด ๋ณ€ํ˜•๋œ ์‹๋ณ„์ž๋ฅผ ์ถ”๊ฐ€๋กœ ํ•ด๋‹น Identifiers์— ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋ชจ๋“  ํ™˜๊ฒฝ์—์„œ ์›ํ™œํžˆ Apple Login์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Firebase Authentication

Firebase ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ๋ถ€ํ„ฐ ์—ฐ๋™๊นŒ์ง€...

Firebase Authentication์„ ์‚ฌ์šฉํ•˜๋Š” ๋ถ„๋“ค์€ ์ถ”๊ฐ€์ ์ธ ์ ˆ์ฐจ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

์šฐ์„  Firebase ์—ฐ๋™์ด ๋˜์–ด์žˆ์ง€ ์•Š๋‹ค๋ฉด ์—ฐ๋™ ํ›„์— ์ ˆ์ฐจ๋ฅผ ์ˆ˜ํ–‰ํ•˜์‹œ๋ฉด ๋œ๋‹ค.

Authentication์„ ์„ ํƒํ•œ ํ›„์— ๋กœ๊ทธ์ธ ๋ฐฉ๋ฒ• ํƒญ์œผ๋กœ ์ด๋™ํ•˜์—ฌ ์ƒˆ ์ œ๊ณต์—…์ฒด๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์ž. ์ œ๊ณต์ฒ˜๋กœ Apple์„ ์„ ํƒํ•ด ํ™œ์„ฑํ™” ํ•ด์ฃผ๋„๋ก ํ•˜์ž.

์ƒ๋‹จ์— ์‚ฌ์šฉ์„ค์ •์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ํ•˜๋‹จ์— ๋„๋ฉ”์ธ์„ ๋ณต์‚ฌํ•ด์„œ ์ €์žฅ์„ ๋ˆŒ๋Ÿฌ์ฃผ์ž.

์—ฌ๊ธฐ์„œ ํ•˜๋‹จ์— ์ƒ์„ฑ๋œ ๋„๋ฉ”์ธ์ด ๋ฐ”๋กœ ์œ„์—์„œ ์‚ดํŽด๋ณธ Server-to-Server Notification Endpoint์˜ URL์ด ๋œ๋‹ค.

์œ„์—์„œ๋„ ์„ค๋ช… ํ–ˆ๋“ฏ์ด ํ•„์ˆ˜ ์‚ฌํ•ญ์€ ์•„๋‹ˆ๊ณ , ํ•ด๋‹น ๋„๋ฉ”์ธ์„ Apple Developer์— ๋“ฑ๋กํ•˜์ง€ ์•Š์•„๋„ Apple Login ๊ธฐ๋Šฅ ์ž์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ๊ณ„์ • ๋ณ€ํ™”์— ๋Œ€ํ•œ ์•Œ๋ฆผ ๊ตฌ๋…์„ ๋ฐ›์ง€ ๋ชปํ•˜๋‹ˆ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

Identifiers ํƒญ์—์„œ ์ƒ์„ฑํ•œ ์‹๋ณ„์ž๋ฅผ ์„ ํƒ ํ›„ ํ™œ์„ฑํ™”ํ•œ Sign in with Apple ๊ธฐ๋Šฅ์˜ Edit์œผ๋กœ ์ ‘๊ทผํ•˜๋ฉด ํ•ด๋‹น ๋„๋ฉ”์ธ์„ ๋„ฃ์–ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

Apple Login ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋ธ”๋กœ๊ทธ๋‚˜ ๊ด€๋ จ ๋„ํ๋จผํŠธ๋ฅผ ๋ณด์‹  ๋ถ„๋“ค ์ค‘์—์„œ๋Š” ๋‚˜์™€์žˆ๋Š” ๋‚ด์šฉ๋งˆ๋‹ค ์ผ๋ถ€ ์„ค์ •์„ ๋‹ค๋ฅด๊ฒŒ ์„ค๋ช…ํ•˜๊ณ  ์žˆ์–ด ํ—ท๊ฐˆ๋ฆฌ์‹  ๋ถ€๋ถ„๋“ค์ด ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค.

์„ค์ •์ด ์กฐ๊ธˆ์”ฉ ๋‹ค๋ฅธ ์ด์œ ๋Š” ์•„๋งˆ๋„ Android๋‚˜ Web์— ํ•„์š”ํ•œ ์„ค์ •์ด ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ํ•ด์„œ ๊ทธ๋Ÿฐ๊ฒ๋‹ˆ๋‹ค.
Firebase Authentication ์„ค์ •๊ณผ ๊ด€๋ จํ•ด์„œ๋„ ์–ด๋–ค ID๋กœ ์‹๋ณ„์ž๋ฅผ ์ƒ์„ฑํ•˜์˜€๊ณ , ์–ด๋–ค ์„œ๋ฒ„ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•ด์„œ ์‚ฌ์šฉ ํ•˜๋Š”์ง€์— ๋”ฐ๋ผ์„œ ์กฐ๊ธˆ์”ฉ ์„ค์ •์ด ๋‹ค๋ฅด๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

๋งŒ์ผ iOS์—์„œ๋งŒ Apple Login ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ ํ•˜์‹ ๋‹ค๋ฉด ์—ฌ๊ธฐ๊นŒ์ง€ ์„ค์ •ํ•˜์‹œ๋ฉด ๋˜๊ณ , ๋‚˜๋จธ์ง€ ์„ค์ •๋“ค์€ ๋ถˆํ•„์š”ํ•œ ์„ค์ •์ด ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•„์š” ์—†๋Š” ์„ค์ •๋“ค์ด ์ถ”๊ฐ€๋˜์–ด ์žˆ์–ด๋„ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ณ  ์šด์˜ํ•˜๋Š”๋ฐ๋Š” ์ „ํ˜€ ๋ฌธ์ œ๊ฐ€ ์—†๋Š” ๊ฒƒ๋„ ๋งž์ง€๋งŒ ์‹œ๊ฐ„์ด ํ๋ฆ„์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๊ฐœ๋ฐœ์ž์˜ ์†์„ ํƒ€๋ฉด์„œ ์šด์˜์ด ๋˜๋‹ค๋ณด๋ฉด ์œ ์ง€๋ณด์ˆ˜๋Š” ์ ์  ์–ด๋ ค์›Œ์ง€๊ธฐ ๋งˆ๋ จ์ด๋ผ ์ตœ๋Œ€ํ•œ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ํŽธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜๋„ ๊ถ๊ธˆํ•˜์‹  ๋ถ€๋ถ„๋“ค์ด ์žˆ์œผ๋‹ˆ ๋ช‡ ๊ฐ€์ง€ ์„ค์ •์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํ•œ๊ฒŒ๋งŒ ์‚ดํŽด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋จผ์ € App IDs์™€ Services IDs๋ฅผ ์–ด๋–ค ํƒ€์ž…์—์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋ฉด, App ID๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ iOS์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด Services ID๋Š” ์›น ์„œ๋น„์Šค์™€ ํ†ตํ•ฉ์ด ํ•„์š”ํ•˜๊ฑฐ๋‚˜ OAuth ๊ธฐ๋ฐ˜์˜ ์ธ์ฆ ํ๋ฆ„์„ ๊ตฌํ˜„ํ•˜๊ณ  ์•ฑ๊ณผ ์›น๊ฐ„์˜ ๋ฆฌ๋‹ค์ด๋ ‰์…˜์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ Apple ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•  ๋•Œ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์‹๋ณ„์ž ์ž…๋‹ˆ๋‹ค.

Apple Login์—์„œ๋Š” Android์—์„œ OAuth ๊ธฐ๋ฐ˜์˜ ์ธ์ฆ์„ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด Services ID๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๋‹ค์Œ์€ Key๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์ธ๋ฐ, Apple๊ณผ์˜ ๋ณด์•ˆ ํ†ต์‹ ์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์œผ๋กœ, Apple Login์—์„œ๋Š” ์ธ์ฆ ๋ฐ JWT ์„œ๋ช…์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Implementing Apple Sign-In

์ด์ œ Flutter ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ๊ตฌํ˜„ํ•ด ๋ณด๋„๋ก ํ•˜์ž.

๋จผ์ € Apple Login์„ ํ”Œ๋žซํผ ์ฑ„๋„์„ ํ†ตํ•ด ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ์ง์ ‘ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์—ฌ๊ธฐ์„œ๋Š” ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด ์ฃผ๋„๋ก ํ•˜๊ฒ ๋‹ค.

Add dependencies

dependencies:
	sign_in_with_apple: ^6.1.4

Firebase ์‚ฌ์šฉ์‹œ firebase_auth ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•˜์ž.

Sign in with Apple

Apple ๋กœ๊ทธ์ธ์„ ์œ„ํ•œ Developer ์„ค์ •์— ์ด์ด์„œ XCode์—์„œ๋„ Sign in with Apple ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™” ํ•ด์ฃผ์ž.

Signing & Capabilities ํƒญ์œผ๋กœ ์ด๋™ํ•˜์—ฌ Capabilities ์ถ”๊ฐ€๋ฅผ ๋ˆŒ๋Ÿฌ Sign in with Apple์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

iOS ๊ฐœ๋ฐœ์— ๊ด€๋ จํ•ด์„œ ์ต์ˆ™ํ•˜์ง€ ์•Š์œผ์‹  ๋ถ„๋“ค์€ ์ €๊ฑธ ์™œ ์ถ”๊ฐ€ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•˜์‹ค ์ˆ˜๋„ ์žˆ๋‹ค. ์ถ”๊ฐ€ํ•˜๋ฉด ๊ทธ๋ƒฅ ๋ชฉ๋ก์—๋งŒ ์ถ”๊ฐ€๋˜์ง€ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์ด ์žˆ๊ฑฐ๋‚˜ ๊ทธ๋ ‡์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ผ ๊ฒƒ์ด๋‹ค.

Capabilities๋Š” ์ฃผ๋กœ Apple์˜ ์‹œ์Šคํ…œ๊ณผ ๊ด€๋ จ๋œ ๊ธฐ๋Šฅ๋“ค์˜ ํ™œ์„ฑํ™”๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๋‹น ๊ธฐ๋Šฅ์ด ํ™œ์„ฑํ™” ๋˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ๋ฐฐํฌ๊ฐ€ ์ด๋ค„์ง€๋ฉด ๊ธฐ๋Šฅ์ด ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.

Apple ์‹œ์Šคํ…œ(์—ฌ๊ธฐ์„œ๋Š” iOS) API๋Š” ์•ฑ์˜ Capabilities ์„ค์ •์„ ๋ฐ”ํƒ•์œผ๋กœ ์‹œ์Šคํ…œ์˜ ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— XCode์—์„œ๋„ Capabilities ์ถ”๊ฐ€๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ๊ฒƒ์ด๋‹ค.

๋Œ€ํ‘œ์ ์ธ Capabilities ๊ธฐ๋Šฅ๋“ค๋กœ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ž˜ ์•Œ๊ณ  ์žˆ๋Š” ์‹œ์Šคํ…œ API์ธ Notifications, Apple Pay, iCloud, HealthKit, App Groups ๋“ฑ์ด ์žˆ๋‹ค.

์• ํ”Œ ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์‹œ์—๋Š” ๊นŒ๋‹ค๋กœ์šด ์• ํ”Œ์˜ ๋””์ž์ธ ์ •์ฑ…์„ ์ค€์ˆ˜ํ•˜์—ฌ์•ผ ํ•œ๋‹ค. ๋‹น์—ฐํžˆ ์ค€์ˆ˜ํ•˜์ง€ ์•Š๊ณ  ์ œ๋ฉ‹๋Œ€๋กœ UI๋ฅผ ๋ฐ˜์˜ํ•˜๊ฒŒ ๋˜๋ฉด Apple ์‹ฌ์‚ฌ ๊ฑฐ์ ˆ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.

Sign in with Apple - Human Interface Guidelines ๊ธฐ์ค€์„ ํ™•์ธํ•œ ํ›„ UI์— ๋ฐ˜์˜ํ•˜์—ฌ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค๋„๋ก ํ•˜์ž.

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•˜๊ฒŒ ๋œ๋‹ค. scopes ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ํ•„์ˆ˜ ๊ฐ’์œผ๋กœ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋‹ค๋ฉด ๋นˆ ๋ฐฐ์—ด๋กœ ์š”์ฒญํ•ด๋„ ์ƒ๊ด€ ์—†๋‹ค.

await SignInWithApple.getAppleIDCredential(scopes: [
	// AppleIDAuthorizationScopes.email,
	// AppleIDAuthorizationScopes.fullName,
]);
None [ email ] [ fullName ] [ email, fullName ]

์• ํ”Œ ๋กœ๊ทธ์ธ์œผ๋กœ ์ œ๊ณต ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋Š” email, fullName ์ด๊ฒŒ ๋์ด๋‹ค...

์ •์ฑ…์ƒ ๊ฐœ์ธ์ •๋ณด๋ฅผ ์—„๊ฒฉํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ œํ•œ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณต ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, Email์ธ ๊ฒฝ์šฐ๋Š” ์‹ฌ์ง€์–ด Hide My Email(์ด๋ฉ”์ผ ๊ฐ€๋ฆฌ๊ธฐ) ์˜ต์…˜์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด ์‹ค์ œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๊ฐ€ ์•„๋‹Œ ๊ฐ€์ƒ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์–ป๊ฒŒ ๋  ์ˆ˜๋„ ์žˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ์†Œ์…œ ์ œ๊ณต์—…์ฒด๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ์กฐ์ฐจ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๊ฐ€ ์—†๋‹ค.

์• ํ”Œ ๋กœ๊ทธ์ธ์ด ๋‹ค๋ฅธ ์†Œ์…œ ๋กœ๊ทธ์ธ์— ๋น„ํ•ด ๊นŒ๋‹ค๋กœ์šด ๋ถ€๋ถ„ ์ค‘์— ํ•˜๋‚˜๋Š” ๋ฐ”๋กœ ์ตœ์ดˆ ๋กœ๊ทธ์ธ ์š”์ฒญ์‹œ์— ํ•œ ๋ฒˆ๋งŒ email, fullName๋“ฑ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณต ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค..

์ตœ์ดˆ ํ•œ ๋ฒˆ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•œ ํ›„ ๋ถ€ํ„ฐ๋Š” null์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ •๋ง null์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ credential์„ ์ถœ๋ ฅํ•ด ๋ณด๋„๋ก ํ•˜์ž.

์ตœ์ดˆ ์š”์ฒญ์‹œ์—๋Š” ์ด๋ฆ„๊ณผ ๋ฉ”์ผ์ •๋ณด๋ฅผ ์ •์ƒ์ ์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ ๊ทธ ์ด ํ›„๋ถ€ํ„ฐ๋Š” null๋กœ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹ค์ œ๋กœ ์• ํ”Œ๋กœ๊ทธ์ธ ํ™”๋ฉด์—์„œ๋„ ์ตœ์ดˆ ๋กœ๊ทธ์ธ๊ณผ ์ด ํ›„ ๋กœ๊ทธ์ธ์˜ ํ™”๋ฉด๋„ ๋‹ค๋ฅด๊ฒŒ ๋‚˜ํƒ€๋‚œ๋‹ค.

์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ์ž๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์„๊นŒ ? ์• ํ”Œ์€ ์‚ฌ์šฉ์ž ๊ณ ์œ  ์‹๋ณ„์ž๋กœ userIdentifier๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์–ด์„œ userIdentifier๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉ์ž ๊ฒ€์ฆ์— ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

Email Options

์• ํ”Œ์ด ์ œ๊ณตํ•˜๋Š” Email์— ๋Œ€ํ•ด์„œ ์ข€ ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด์ž.

์• ํ”Œ ๋กœ๊ทธ์ธ์‹œ์— ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์€ Share My Email, Hide My Email ์ด๋ ‡๊ฒŒ 2๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ๋‹ค.

Share My Email(์ด๋ฉ”์ผ ๊ณต์œ )์€ ์‹ค์ œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ ์ผ๋ฐ˜์ ์ธ ์†Œ์…œ ๋กœ๊ทธ์ธ๊ณผ ๋‹ค๋ฅธ๊ฒŒ ์—†์ง€๋งŒ Hide My Email(์ด๋ฉ”์ผ ๊ฐ€๋ฆฌ๊ธฐ)์€ ๊ฐ€์ƒ์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ์ธ ๊ฒƒ์ด๋‹ค.

์ด๋ฉ”์ผ๊ณผ ๊ด€๋ จ๋œ ์˜ต์…˜์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ์„ ํƒ์ ์œผ๋กœ ์š”์ฒญํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜์žˆ์œผ๋ฉฐ, ์•ฑ ์‚ฌ์šฉ์— ์žˆ์–ด์„œ ์ด๋ฉ”์ผ ๊ฐ€๋ฆฌ๊ธฐ๋ฅผ ์„ ํƒํ•œ ์‚ฌ์šฉ์ž๋ฅผ ์•ฑ ๋‚ด์—์„œ ์ง„์ž…์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์˜๋ฌด์ ์œผ๋กœ ์‹ค์ œ ์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•˜๋„๋ก ํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค๊ณ  ํ•œ๋‹ค (์•„๋งˆ๋„ ๋ฆฌ์  ์‚ฌ์œ ์ธ ๋“ฏ...).

Hide My Email ์˜ต์…˜์œผ๋กœ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์— ํ•œํ•ด์„œ ์• ํ”Œ์€ ๊ฐ€์ƒ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ Private Reley Email์„ ์ƒ์„ฑํ•ด ์ œ๊ณตํ•˜๊ฒŒ ๋œ๋‹ค.

Private Reley Email์€ ์•ฑ๋งˆ๋‹ค ๊ณ ์œ ํ•˜๊ฒŒ ์ƒ์„ฑ์ด ๋˜๊ณ , ํ•ด๋‹น ์ด๋ฉ”์ผ๋กœ ๋ฉ”์ผ์„ ๋ณด๋‚ด๋ฉด, ์‹ค์ œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ๋ฉ”์ผ์„ ์ „์†กํ•ด์ฃผ๋Š” Forwarding ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์‚ฌ์•ˆ๋„ ์žˆ๋Š”๋ฐ ๋ฐ”๋กœ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ˜๋™์œผ๋กœ ๋ฉ”์ผ์˜ ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์‹œ ์ด๋ฉ”์ผ ์™ธ์˜ ์—ฐ๊ฒฐ ์ˆ˜๋‹จ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋งŒ์ผ ์ˆ˜๋™์œผ๋กœ ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•˜์ง€๋งŒ ์•Š๋Š”๋‹ค๋ฉด ์˜๊ตฌ์ ์œผ๋กœ ๋งŒ๋ฃŒ๋˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

*Private Reley Email๊ณผ ๊ด€๋ จํ•ด์„œ๋Š” ์ถ”ํ›„ ์ž์„ธํ•œ ๋‚ด์šฉ์œผ๋กœ ์ž‘์„ฑํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

Authentication

์•ฑ์—์„œ ์ •์ƒ์ ์œผ๋กœ ์• ํ”Œ ๋กœ๊ทธ์ธ์ด ์ˆ˜ํ–‰๋˜๊ณ  ๋‚˜๋ฉด, ๊ฐ ํ™˜๊ฒฝ์— ๋”ฐ๋ฅธ ๋‹ค์Œ ์Šคํ…์„ ์ง„ํ–‰ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.
์ผ๋ฐ˜์ ์œผ๋กœ ์• ํ”Œ ๋กœ๊ทธ์ธ๊ณผ ๊ฐ™์€ ์†Œ์…œ ๋กœ๊ทธ์ธ์€ ํ•˜๋‚˜์˜ ์ธ์ฆ ์ˆ˜๋‹จ์ผ ๋ฟ์ด๊ธฐ ๋•Œ๋ฌธ์—, ๊ณ ์œ  ID๋ฅผ ์‚ฌ์šฉํ•ด ์•ฑ ๋‚ด๋ถ€์—์„œ ๋ณ„๋„๋กœ ์ธ์ฆ์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋  ๊ฒƒ์ธ๋ฐ, ํ•ด๋‹น ์ ˆ์ฐจ๋Š” ํ˜„์žฌ ์„œ๋น„์Šค์˜ ๋‚ด๋ถ€ ์ ˆ์ฐจ๋Œ€๋กœ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

์ถ”๊ฐ€์ ์œผ๋กœ ์„œ๋ฒ„์—์„œ Apple ID ๋Œ€ํ•œ ๊ฒ€์ฆ์„ ๊ฑฐ์ณ์•ผ ํ•œ๋‹ค๋ฉด, ์•ฑ์—์„œ ๋กœ๊ทธ์ธ ์„ฑ๊ณต ํ›„ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฐ์ดํ„ฐ ์ค‘ authorizationCode, identityToken์„ ์„œ๋ฒ„์— ์ „๋‹ฌํ•˜์—ฌ ์• ํ”Œ๋กœ ๋ถ€ํ„ฐ ํ† ํฐ ๊ฒ€์ฆ์„ ์š”์ฒญ ํ•˜๋Š” ๋“ฑ์˜ ์ ˆ์ฐจ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

Authorization Exception

sign_in_with_apple ํŒจํ‚ค์ง€ ์‚ฌ์šฉ์‹œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ดํŽด๋ณด์ž.

Exception ์ฒ˜๋ฆฌ์‹œ SignInWithAppleAuthorizationException์„ ์บ์น˜ํ•ด์„œ ์—๋Ÿฌ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. AuthorizationErrorCode๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ, ์˜ˆ์™ธ ํƒ€์ž…์€ 6๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

enum AuthorizationErrorCode {
	canceled, failed, invalidResponse, notHandled, notInteractive, unknown
}

์˜ˆ์™ธ ์ผ€์ด์Šค์— ๋Œ€ํ•œ ์„ค๋ช…์€ ํ•ด๋‹น ํŒจํ‚ค์ง€ ํŒŒ์ผ์„ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ๋œ๋‹ค.

Firebase Authentication

Firebase Authentication์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ ์ธ์ฆ ๋ฐฉ์‹๊ณผ ๋™์ผํ•˜๊ฒŒ ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ์—ฐ๊ฒฐํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์• ํ”Œ ๋กœ๊ทธ์ธ ์ธ์ฆ ์„ฑ๊ณต์‹œ ๋ฐ˜ํ™˜๋˜๋Š” identityToken
๊ณผ authorizationCode๋ฅผ Authentication์˜ OAuthProvider๋กœ ์ „์†กํ•ด ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ๋งˆ๋ฌด๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ, provider๋กœ apple.com์„ ์‚ฌ์šฉํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

final OAuthCredential authCredential = OAuthProvider("apple.com").credential(
        idToken: credential.identityToken,
        accessToken: credential.authorizationCode,
);

์ƒ์„ฑ๋œ OAuthCredential์œผ๋กœ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•ด UserCredential์„ ์ •์ƒ์ ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

final UserCredential user = await FirebaseAuth.instance.signInWithCredential(authCredential);

Code

Future<void> signInWithApple() async {
    try {
      final AuthorizationCredentialAppleID credential =
          await SignInWithApple.getAppleIDCredential(scopes: [
        AppleIDAuthorizationScopes.email,
        AppleIDAuthorizationScopes.fullName,
      ]);
      
      print(credential.userIdentifier);

	  // [Optional] Firebase Authentication ์—ฐ๋™ ์‹œ ์ ˆ์ฐจ
      final OAuthCredential authCredential = OAuthProvider("apple.com").credential(
        idToken: credential.identityToken,
        accessToken: credential.authorizationCode,
      );
      final UserCredential user =
          await FirebaseAuth.instance.signInWithCredential(authCredential);

	} on SignInWithAppleAuthorizationException catch (e) {
      // Handling errors on failure
    } catch (_) {
      // Handling other errors
    }
  }

Revoking Apple Login Tokens

Sign in with Apple ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ๋””๋ฒจ๋กœํผ ์„ธํŒ…, ์• ํ”Œ ๋กœ๊ทธ์ธ ์š”์ฒญ, ๋งˆ์ง€๋ง‰์œผ๋กœ ์‚ฌ์šฉ์ž ์ธ์ฆ๊นŒ์ง€ ์™„๋ฃŒ๋ฅผ ํ–ˆ๋‹ค.

๊ณผ์—ฐ ๋ชจ๋“  ์ ˆ์ฐจ๊ฐ€ ๋๋‚œ๊ฑธ๊นŒ ?

์•„๋‹ˆ๋‹ค. Apple ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•˜๋Š” ๊ฒƒ ๋งŒํผ์ด๋‚˜ ์ค‘์š”ํ•œ ์ž‘์—…์ด ๋‚จ์•„์žˆ๋‹ค. ๋ฐ”๋กœ ํ† ํฐ ๋ฌดํšจํ™”(Revoke Token)๊ธฐ๋Šฅ์ด๋‹ค.

์‚ฌ์‹ค ์• ํ”Œ ๋กœ๊ทธ์ธ๊ณผ ๊ด€๋ จํ•ด์„œ๋Š” ๊ด€๋ จ ๋‚ด์šฉ์ด๋‚˜ ์ •๋ณด๋ฅผ ์‰ฝ๊ฒŒ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๊ณ , ์ด๋ฏธ ๋งŽ์€ ๊ฐœ๋ฐœ์ž ๋ถ„๋“ค์ด ์ƒ์„ธํ•˜๊ฒŒ ๊ธ€์„ ์ž‘์„ฑํ•ด์ฃผ์…”์„œ ๋ณ„๋„๋กœ ๊ธ€์„ ์ž‘์„ฑํ•  ๊ณ„ํš์€ ์—†์—ˆ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ช‡ ๋…„๋งŒ์— ์‹ ๊ทœ ์„œ๋น„์Šค ์ถœ์‹œ ๊ธฐํšŒ๊ฐ€ ์žˆ์–ด์„œ ์• ํ”Œ ๋กœ๊ทธ์ธ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ, ์˜ค๋žœ๋งŒ์— ํ•ด๋ณด๋‹ˆ๊น ๊ธฐ์–ต๋„ ์ž˜ ์•ˆ๋‚˜๊ณ  ๊ทธ๋ž˜์„œ ์ด์ฐธ์— ์„ธ์„ธํ•˜๊ฒŒ ์ •๋ฆฌ๋ฅผ ํ•ด์•ผ๊ฒ ๋‹ค๋Š” ๋งˆ์Œ์ด ์ƒ๊ฒจ์„œ ๊ธ€์„ ์ž‘์„ฑํ•˜๊ฒŒ ๋œ ๊ฒƒ์ด์—ˆ๋‹ค.

์„ธ์„ธํ•˜๊ฒŒ ์ •๋ฆฌ๊ฐ€ ํ•„์š”ํ–ˆ๋˜ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ ํ† ํฐ ๋ฌดํšจํ™”(Revoke Token) ๊ธฐ๋Šฅ์ธ๋ฐ, ์ด ๊ธฐ๋Šฅ์€ ์„œ๋ฒ„ ํ™˜๊ฒฝ์„ ๊ฐ–์ถ˜ ์„œ๋น„์Šค์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ ์ž…์žฅ์œผ๋กœ๋Š” ํฌ๊ฒŒ ๊ณ ๋ฏผํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ธฐ๋Šฅ์ด๊ธด ํ•˜๋‹ค. ๋งŒ์ผ ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ์ œ๊ณตํ•˜๋Š” ์„œ๋น„์Šค์ธ๋ฐ ํ† ํฐ ๋ฌดํšจํ™”์— ๋Œ€ํ•ด์„œ ์ž˜ ๋ชจ๋ฅด์‹ ๋‹ค๋ฉด ์•„๋งˆ๋„ ์šด์˜ํ•˜๋Š” ์„œ๋น„์Šค์˜ ๋ฐฑ์—”๋“œ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค.

์• ํ”Œ์—์„œ๋Š” ์„œ๋ฒ„์—์„œ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ•˜๋Š” ์š”์ฒญ์ธ๋ฐ, 1์ธ ๊ฐœ๋ฐœ ๋˜๋Š” Serverless ํ™˜๊ฒฝ์—์„œ ์šด์˜์„ ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์–ด์ฉ” ์ˆ˜ ์—†์ด ๊ฒฐ๊ตญ ํด๋ผ์ด์–ธํŠธ์—์„œ ํ•ด๊ฒฐํ•ด ์ฃผ์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ์—์„œ ํ† ํฐ ๋ฌดํšจํ™”(Revoke Token)๋ฅผ ์–ด๋–ป๊ฒŒ ์š”์ฒญํ•˜๊ณ  ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

ํ† ํฐ ๋ฌดํšจํ™”(Revoke Token)๋ž€ ๋ฌด์—‡์ผ๊นŒ? ์‚ฌ์‹ค ๋ณ„๊ฑฐ ์—†๋‹ค. ์„œ๋น„์Šค์™€ ์• ํ”Œ ๊ณ„์ • ๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•ด ์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

์• ํ”Œ์—์„œ๋งŒ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ธฐ๋Šฅ์€ ์•„๋‹ˆ๊ณ  ๋ชจ๋“  ์†Œ์…œ ๋กœ๊ทธ์ธ ์—…์ฒด๊ฐ€ ์š”๊ตฌํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

ํšŒ์› ํƒˆํ‡ด์‹œ๋‚˜ ๊ณ„์ •์„ ๋น„ํ™œ์„ฑํ™”ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ง€์šฐ๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ฒŒ ๋˜๋”๋ผ๋„ ์†Œ์…œ ๋กœ๊ทธ์ธ๊ณผ์˜ ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง€๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๊ฐ ์†Œ์…œ ๋กœ๊ทธ์ธ์˜ ์—ฐ๊ฒฐ๋œ ๊ณ„์ •์„ ์‚ดํŽด๋ณด๋ฉด ๋‚ด๊ฐ€ ํƒˆํ‡ดํ•œ ์„œ๋น„์Šค๊ฐ€ ์•„์ง๋„ ์ œ๊ณต๋œ ์„œ๋น„์Šค๋กœ ๋œจ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์€๋ฐ, ๋‚ด ๊ณ„์ •๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ํ•ด๋‹น ์„œ๋น„์Šค์—์„œ ํ•ด์ œ๋ฅผ ์š”์ฒญํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ์ „ํžˆ ์—ฐ๊ฒฐ๋œ ์ƒํƒœ๋กœ ๋‚จ์•„์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด ์• ํ”Œ ๋กœ๊ทธ์ธ์€ ์ตœ์ดˆ ์—ฐ๊ฒฐ์‹œ์—๋งŒ email, fullName ์ •๋ณด๋ฅผ ๋ฐ˜ํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งŒ์ผ ํƒˆํ‡ดํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์žฌ ๊ฐ€์ž…์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜์—ˆ์„ ๋•Œ์—๋„ ์—ฐ๊ฒฐ์ด ๋Š์–ด์ ธ ์žˆ์ง€ ์•Š๋‹ค๋ฉด, ์ด๋Ÿฌํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†๋‹ค.
๊ฐœ์ธ์ •๋ณด๊ฐ€ ์ค‘์š”ํ•œ ๋งŒํผ, ์ •์ƒ์ ์œผ๋กœ ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•˜์—ฌ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•˜์ž.

ํ† ํฐ ๋ฌดํšจํ™”(Revoke Token)๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ ˆ์ฐจ์— ๋Œ€ํ•ด์„œ ๋จผ์ € ์„ค๋ช…ํ•˜๊ฒ ๋‹ค.

1. ์• ํ”Œ ๋กœ๊ทธ์ธ์œผ๋กœ authorizationCode ํ™•์ธ
2. JWT(Client Secret) ์ƒ์„ฑ
3, AccessToken or RefreshToken ๋ฐœ๊ธ‰
4. Revoke ์š”์ฒญ

์ ˆ์ฐจ๋ฅผ ๋ณด๋ฉด ๋งŽ์ด ๋ณต์žกํ•ด ๋ณด์ด์ง€๋Š” ์•Š๋Š”๋ฐ, ํ•ด์•ผํ•  ์ž‘์—…์ด ์ƒ๊ฐ๋ณด๋‹ค๋Š” ๋งŽ์Šต๋‹ˆ๋‹ค.. ์ž˜ ๋”ฐ๋ผํ•˜์…”์„œ ๋ชจ๋‘ ์ž˜ ๊ตฌํ˜„ํ•˜์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

JWT(Client Secret) ์ƒ์„ฑ์„ ์œ„ํ•ด์„œ๋Š” ์•”ํ˜ธํ™”๋œ ํ”„๋ผ์ด๋น— ํ‚ค๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์•„ ํ† ํฐ ์ƒ์„ฑ์‹œ ์ธ์ฆ์„ ์ง„ํ–‰ํ•ด ์ฃผ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ์„  ํ‚ค๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๋„๋ก ํ•˜์ž.

Developer์— Keys ํƒญ์—์„œ ์ƒ์„ฑ์„ ์ง„ํ–‰ํ•ด ์ฃผ๋ฉด ๋˜๋Š”๋ฐ, ๋งŒ์•ฝ์— Sign in with Apple ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ์„œ๋น„์Šค๋กœ ํ‚ค๋ฅผ ์ด๋ฏธ ๋ฐœ๊ธ‰๋ฐ›์€ ์ƒํƒœ๋ผ๋ฉด ๊ธฐ์กด ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์…”์•ผ ํ•œ๋‹ค.

Key ๋ฐœ๊ธ‰ ํ›„ ๋‹จ ํ•œ๋ฒˆ๋งŒ ๋‹ค์šด๋กœ๋“œ ๊ฐ€๋Šฅํ•จ - ์ž˜ ๋ณด๊ด€ํ•ด์•ผ ํ•จ.

Key Name๊ณผ Description์„ ์ž‘์„ฑํ•ด์ฃผ์ž. ์šด์˜์ค‘์ธ ์„œ๋น„์Šค์˜ ํ‚ค๋Š” ์‚ญ์ œ๋˜๋ฉด ๋ณต์žกํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ˜๋“œ์‹œ Key ๊ด€๋ฆฌ๋Š” ์‹ ์ค‘ํ•˜๊ฒŒ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ๋„ค์ด๋ฐ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์„œ๋น„์Šค๋ช…์„ ๋„ฃ์–ด์ค€๋‹ค.

ํ•˜๋‹จ์— Sign in with Apple ๊ธฐ๋Šฅ์„ ์ฒดํฌํ•˜๊ณ  Configure๋ฅผ ๋ˆŒ๋Ÿฌ์ฃผ์ž.

๊ธฐ์กด ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์‹œ๋Š” ๊ฒฝ์šฐ์—๋Š” ๊ธฐ์กด ํ‚ค๋ฅผ ์„ ํƒํ•ด ์ ˆ์ฐจ๋ฅผ ์ˆ˜ํ–‰ํ•˜์‹œ๋ฉด ๋œ๋‹ค.

์„œ๋น„์Šคํ•˜๋Š” ์•ฑ์„ ์„ ํƒํ•ด ์ €์žฅํ•˜๊ณ  ๋ฐœ๊ธ‰ ์ •๋ณด๊ฐ€ ๋งž์œผ๋ฉด Register๋ฅผ ๋ˆŒ๋Ÿฌ ํ‚ค๋ฅผ ์ƒ์„ฑํ•ด์ฃผ์ž.

์—ฌ๊ธฐ์„œ Download ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ๋˜๋ฉด ๋‹ค์šด๋กœ๋“œ ํ•˜์ž.

๋‹ค์šด๋กœ๋“œ๋Š” ๋‹จ ํ•œ๋ฒˆ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ˆ, ๋‹ค์šด๋ฐ›์€ .p8 ํŒŒ์ผ์€ ์žƒ์–ด๋ฒ„๋ฆฌ์ง€ ์•Š๊ฒŒ ์ž˜ ๋ณด๊ด€ํ•ด ์ฃผ์ž.

* ํ…Œ์ŠคํŠธ ๋˜๋Š” ์•„์ง ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์–ธ์ œ๋“ ์ง€ ์‚ญ์ œ ํ›„ ์žฌ๋ฐœ๊ธ‰ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ.

์•ž์„œ ์ •๋ฆฌํ•œ ํ”Œ๋กœ์šฐ๋Œ€๋กœ ์ง„ํ–‰์„ ํ•ด๋ณด๋ฉด ํ† ํฐ ๋ฌดํšจํ™”๋ฅผ ์œ„ํ•ด ํ•ด๊ฒฐ ํ•ด์•ผํ•  ๋ถ€๋ถ„์ด authorizationCode๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ถ€๋ถ„ํ•˜๊ณ , JWT๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์ผ ๊ฒƒ์ด๋‹ค.

์•„๋งˆ๋„ ๊ธฐ์–ต๋‚˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ, authorizationCode๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ถ€๋ถ„์€ ์šฐ๋ฆฌ๊ฐ€ ์ด๋ฏธ ์ง„ํ–‰ํ•œ ๋‚ด์šฉ์ด์—ˆ๋‹ค. ๋ฐ”๋กœ ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ํ†ตํ•ด์„œ ์–ป์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

OAuth 2.0 ์ธ์ฆ ํ”„๋กœ์„ธ์Šค์—์„œ Token์„ ๋ฐœ๊ธ‰ ๋ฐ›๊ธฐ ์œ„ํ•œ ์ผํšŒ์„ฑ ์ฝ”๋“œ๊ฐ€ authorizationCode ์ด๋‹ค. ํ•ด๋‹น ์ฝ”๋“œ๋Š” ๋งŒ๋ฃŒ ์‹œ๊ฐ„์ด ์งง๊ณ , ์ผํšŒ์„ฑ ์ฝ”๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„๋กœ ๋ณด๊ด€ํ•œ๋‹ค๊ณ  ํ•ด๋„ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋กœ ์ธํ•˜์—ฌ ํšŒ์› ํƒˆํ‡ด๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ, ์†Œ์…œ ๊ณ„์ •๊ณผ์˜ ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•˜๊ฒŒ ๋˜๋Š”๊ฒƒ์ด๋‹ค.

authorizationCode๋Š” ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•ด ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์œผ๋‹ˆ, ๋‹ค์Œ์œผ๋กœ JWT ์ƒ์„ฑ ๋ถ€๋ถ„์„ ์‚ดํŽด๋ณด์ž.

Apple OAuth ํ”„๋กœ์„ธ์„œ์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ธ์ฆ ์„œ๋ฒ„์— ์š”์ฒญํ•  ๋•Œ Client Secret์„ ์‚ฌ์šฉํ•ด ์ธ์ฆ ์š”์ฒญ์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด Client Secret์€ ์‚ฌ์‹ค JWT๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

JWT๋ฅผ ์ƒ์„ฑํ•ด Client Secret๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” clientId, teamId, keyId, privateKey๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  • clientId : Bundle Identifier
    XCode์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ
  • teamId
    Apple Developer์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ
  • keyId
    ๋ฐœ๊ธ‰๋ฐ›์€ ์•”ํ˜ธํ™” ํ‚ค์˜ ID
  • privateKey
    .p8 ํŒŒ์ผ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ, ์•”ํ˜ธํ™” ํ‚ค ๋ฐœ๊ธ‰์‹œ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์€ ํŒŒ์ผ์ž„

.p8์ด ์—ด๋ฆฌ์ง€ ์•Š๋Š” ๋ถ„๋“ค์€ ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ๋กœ ์—ด์–ด์ฃผ์‹œ๋ฉด ๋œ๋‹ค.

๐Ÿ”ฅ ์—ฌ๊ธฐ์„œ ๋งค์šฐ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด ์žˆ๋Š”๋ฐ, ์•”ํ˜ธํ™” ํ‚ค์™€ ๊ด€๋ จ๋œ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋„ ๊ณต๊ฐœ๋˜์„œ๋Š” ์•ˆ๋˜๋‹ˆ ๋ฐ˜๋“œ์‹œ ๋…ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด ์ฃผ์„ธ์š” !!!!

์ €๋Š” ์ž„์‹œ๋กœ ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ์„ ์œ„ํ•ด์„œ ๋ฐœ๊ธ‰ ๋ฐ›์€ ํ‚ค์ด๊ธฐ ๋•Œ๋ฌธ์—, ํ•ด๋‹น ๋ธ”๋กœ๊ทธ ๋‚ด์šฉ๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ์•”ํ˜ธํ™” ํ‚ค๋‚˜ ์‹๋ณ„์ž ๋“ค์€ ์ „๋ถ€ ์‚ญ์ œ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„๋“ค์€ ์ ˆ๋Œ€ ๋…ธ์ถœ ์‹œํ‚ค์‹œ๋ฉด ์•ˆ๋˜์š” !!

Adding Required Packages

Flutter์—์„œ JWT์ƒ์„ฑ์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ํŒจํ‚ค์ง€์™€ API ํ˜ธ์ถœ์„ ์œ„ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์ž.

dependencies:
	dart_jsonwebtoken: ^2.17.0
	http: ^1.3.0

Generating JWT for Apple Authentication

์•ž์„œ ์‚ดํŽด๋ณธ id๋‚˜ ํ‚ค๋ฅผ ์˜์—ญ์— ๋งž๊ฒŒ ๋ณ€๊ฒฝํ•ด ์ฃผ์‹œ๋ฉด ๋˜๊ณ , iat, exp๋Š” JWT ์ƒ์„ฑ์‹œ๊ฐ„๊ณผ ๋งŒ๋ฃŒ์‹œ๊ฐ„์„ ๋ช…์‹œํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ๋งŒ๋ฃŒ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋‹น์—ฐํžˆ ์• ํ”Œ ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ์ธ์ฆ์ด ๊ฑฐ๋ถ€๋œ๋‹ค.

๊ฐ์ž๊ฐ€ ๊ตฌํ˜„ํ•˜๋Š” ๋กœ์ง์— ๋งž๊ฒŒ ๋งŒ๋ฃŒ์‹œ๊ฐ„์„ ์„ค์ •ํ•ด ์ฃผ์‹œ๋ฉด ๋œ๋‹ค.

JWT({
	"iss": {your_team_id},
	"iat": DateTime.now().millisecondsSinceEpoch ~/ 1000,
	"exp": (DateTime.now().millisecondsSinceEpoch ~/ 1000) + 3600,
	"aud": "https://appleid.apple.com",
	"sub": {your_client_id},
	},
	header: {
		"alg": "ES256",
        "kid": {your_key_id},
	},
);

์ด์ œ ์ƒ์„ฑํ•œ JWT๋กœ Clent Secret์„ ๊ตฌ์„ฑํ•ด ์ฃผ๋„๋ก ํ•˜์ž.

๊ตฌ์„ฑ์— ์•ž์„œ .p8ํŒŒ์ผ์˜ ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ, ํ‚ค๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์— ์ฃผ์˜ํ•  ๋ถ€๋ถ„์€ ํŒŒ์ผ ๋‚ด์— ๋ชจ๋“  ํ…์ŠคํŠธ๊ฐ€ ํฌํ•จ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ๊ณผ ์ค„๋ฐ”๊ฟˆ ์ƒํƒœ๋„ ์œ ์ง€๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

  • Case 1
const String privateKey =
        "-----BEGIN PRIVATE KEY-----\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgL11OH66VJoxfxZSQ\nTGpTW4vcXPVylbGYigSACKFr212gCgYIKoZIzj0DAQehRANCAARZlXVBlPY2L8Ao\n4kF61H0zzcSpTmEqVU22SJKOnIf3wnS6zNxBfIfl5q7IyUXcr21c5ni5zuMY8OGT\nv3NQQVpd\n-----END PRIVATE KEY-----";
  • Case 2
const String privateKey = '''-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgL11OH66VJoxfxZSQ
TGpTW4vcXPVylbGYigSACKFr212gCgYIKoZIzj0DAQehRANCAARZlXVBlPY2L8Ao
4kF61H0zzcSpTmEqVU22SJKOnIf3wnS6zNxBfIfl5q7IyUXcr21c5ni5zuMY8OGT
v3NQQVpd
-----END PRIVATE KEY-----''';

Client Secret์„ ๋งŒ๋“ค์–ด ์ฃผ๊ธฐ ์œ„ํ•ด ์ƒ์„ฑํ•œ JWT์— Private Key๋กœ ์„œ๋ช…(Signature)์„ ์ง„ํ–‰ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ ES256์€ Apple์ด ์š”๊ตฌํ•˜๋Š” JWT ์„œ๋ช… ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ฉฐ, Elliptic Curve Digital Signature Algorithm(ECDSA)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๋‹ค.

const String privateKey = '''...''';
final JWT jwt = JWT({...});

final String clientSecret = jwt.sign(
	ECPrivateKey(privateKey),
	algorithm: JWTAlgorithm.ES256,
);

Retrieving Access and Refresh Tokens

Client Secret์„ ์ƒ์„ฑ ํ•˜์˜€์œผ๋‹ˆ, ์ด์ œ API ๊ด€๋ จ๋œ ํ†ต์‹ ๋งŒ ์ˆ˜ํ–‰ํ•˜๋ฉด์„œ ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

Apple์˜ Revoke Tokens API๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Access(or Refresh) Token์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ† ํฐ์„ ๋จผ์ € ๋ฐœ๊ธ‰๋ฐ›๋„๋ก ํ•˜์ž.

ํ† ํฐ์€ ์•ž์„œ ์ƒ์„ฑํ•œ Client Secret๊ณผ ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ํ†ตํ•ด ๊ฐ€์ ธ์˜จ authorizationCode๋กœ Access Token ๋˜๋Š” Refresh Token์„ ๋ฐœ๊ธ‰ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

Future<void> getRefreshToken(String authorizationCode) async {
    try {
      final String clientSecret = _createAppleClientSecret();
      final http.Response response = await http.post(
        Uri.parse("https://appleid.apple.com/auth/token"),
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
        },
        body: {
          "client_id": {your_client_id},
          "client_secret": clientSecret,
          "code": authorizationCode,
          "grant_type": "authorization_code",
          "redirect_uri": "REDIRECT_URL",
        },
      );
      if (response.statusCode == 200) {
        // final data = json.decode(response.body);
        // data["refresh_token"];
        // data["access_token"]
      }
    } catch (_) {}
  }

์ •์ƒ์ ์œผ๋กœ Access Token๊ณผ Refresh Token์„ ๋ฐœ๊ธ‰ ๋ฐ›์•˜๋‹ค.

Revoking Tokens

๋“œ๋””์–ด ๋งˆ์ง€๋ง‰์œผ๋กœ Apple์— ์„œ๋น„์Šค์™€์˜ ๊ณ„์ • ์—ฐ๊ฒฐ ํ•ด์ œ๋งŒ ์š”์ฒญํ•˜๋ฉด ๋์ด๋‹ค !

Apple์˜ Revoke Tokens API ์š”์ฒญ์‹œ์—๋„ Client Secret์€ ํ•„์š”ํ•˜๋‹ค.

Revoke Token์˜ API๋Š” ์‘๋‹ต ๊ฐ’์ด ์—†์œผ๋ฉฐ, 200 ์ฝ”๋“œ๋กœ ์„ฑ๊ณต ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ์•„๋‹ˆ๋ฉด ์‚ฌ์šฉํ•œ ํ† ํฐ์„ ๋‹ค์‹œ ๊ฒ€์ฆ ๋ฐ›์•„ ์—ฐ๊ฒฐ ํ•ด์ œ๋ฅผ ํ™•์ธํ•˜๋ฉด ๋œ๋‹ค.

Future<void> revokeToken(String refreshToken) async {
    try {
      final String clientSecret = createClientSecret();
      final http.Response response = await http.post(
        Uri.parse("https://appleid.apple.com/auth/revoke"),
        headers: {"Content-Type": "application/x-www-form-urlencoded"},
        body: {
          "client_id": {your_client_id},
          "client_secret": clientSecret,
          "token": refreshToken,
          "token_type_hint": "refresh_token",
        },
      );
      if (response.statusCode == 200) {
        // success
      }
    } catch (_) {}
  }

์—ฐ๊ฒฐ์ด ์ •์ƒ์ ์œผ๋กœ ํ•ด์ œ ๋˜์—ˆ๋‹ค๋ฉด, Apple์€ ๊ณ„์ • ์ •๋ณด ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์•ˆ๋‚ด Email์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฐœ์†กํ•œ๋‹ค.

Test

Mac ๋˜๋Š” iPhone์—์„œ Apple ๊ณ„์ •์— ์ ‘์†ํ•ด๋ณด๋ฉด, Apple๋กœ ๋กœ๊ทธ์ธํ•œ ๋‚ด์—ญ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Revoke Tokens ์š”์ฒญ์„ ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒํ•˜๊ฒŒ ๋˜๋ฉด ๋‚ด์—ญ์—์„œ ๋” ์ด์ƒ ์—ฐ๊ฒฐ๋œ ์„œ๋น„์Šค๊ฐ€ ๋ณด์ด์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

ํšŒ์› ํƒˆํ‡ด ๋˜๋Š” ๋น„ํ™œ์„ฑํ™” ๋“ฑ์˜ Apple๊ณผ์˜ ๊ณ„์ • ์—ฐ๊ฒฐ์„ ํ•ด์ œํ•˜๊ธฐ ์œ„ํ•œ ์ ˆ์ฐจ๋ฅผ ์ •๋ฆฌํ•ด๋ณด๋ฉด, 1๏ธโƒฃauthorizationCode๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ์š”์ฒญํ•˜๊ณ  2๏ธโƒฃ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JWT ์„œ๋ช… ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ Client Secret์„ ์ƒ์„ฑ, 3๏ธโƒฃAccess (or Refresh) Token์„ ๋ฐœ๊ธ‰ ๋ฐ›์•„ 4๏ธโƒฃRevoke Tokens API๋ฅผ ์š”์ฒญํ•˜๋„๋ก ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

Hiding Private Keys

ํ† ํฐ ๋ฌดํšจํ™”์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜๋Š”๋ฐ, ๋งˆ์ง€๋ง‰์œผ๋กœ ์œ„์—์„œ ์‚ฌ์šฉํ•œ ํ”„๋ผ์ด๋น— ํ‚ค๋ฅผ ์ˆจ๊ธฐ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์†Œ๊ฐœํ•ด ๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

์™œ ์ˆจ๊ฒจ์•ผ ํ• ๊นŒ ? ๊ฐœ๋ฐœ์„ ํ•˜๋ฉด์„œ ํŒ€๊ณผ ํ˜‘์—…ํ•˜๊ฑฐ๋‚˜ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ, ํ”„๋ผ์ด๋น— ํ‚ค(API ํ‚ค, ์„œ๋น„์Šค ๊ณ„์ • ํ‚ค, ์ธ์ฆ ์ •๋ณด ๋“ฑ)๊ฐ€ ์‹ค์ˆ˜๋กœ Git์— ์ปค๋ฐ‹๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.
์ด๋Ÿฌํ•œ ํ‚ค๊ฐ€ ์™ธ๋ถ€์— ๋…ธ์ถœ๋˜๋ฉด ๋ณด์•ˆ ์‚ฌ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•…์˜์ ์ธ ์‚ฌ์šฉ์œผ๋กœ ์ธํ•ด ์‹œ์Šคํ…œ์ด ์œ„ํ—˜์— ์ฒ˜ํ•  ์ˆ˜ ์žˆ๋‹ค. .gitignore, .env, ํ™˜๊ฒฝ ๋ณ€์ˆ˜(Environment Variables), Secret Manager ๋“ฑ์˜ ์ •๋ง ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ํ‚ค๋ฅผ ์ˆจ๊ธฐ๊ณ  ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ๊ฐ ํ™˜๊ฒฝ๊ณผ ํŒ€์˜ ์„ฑ๊ฒฉ์— ๋งž๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•„ ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋œ๋‹ค.

์ด๋ฒˆ์— ์†Œ๊ฐœํ•  ๋ฐฉ๋ฒ•์€ Configiguration File๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

๋น„๊ณต๊ฐœ ํ‚ค๋‚˜ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์„ค์ •, ๋นŒ๋“œ ๋ณ€ํ˜•์— ๋”ฐ๋ฅธ ํ™˜๊ฒฝ ์„ค์ • ๋“ฑ์„ Config ํŒŒ์ผ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ์™ธ๋ถ€ ์ €์žฅ์†Œ์— ์˜ฌ๋ฆฌ์ง€ ์•Š๊ณ  ํŒ€ ๋‚ด์—์„œ๋งŒ ๊ณต์œ ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•˜๋‹ค .gitignore์— Config ํŒŒ์ผ์„ ๋“ฑ๋กํ•˜์—ฌ ์™ธ๋ถ€ ์ €์žฅ์†Œ์— ์ปค๋ฐ‹๋˜์ง€ ์•Š๋„๋ก ํ•˜๊ณ , Config ํŒŒ์ผ์„ ์•ฑ ์ดˆ๊ธฐ ์„ค์ • ๋˜๋Š” ํ•„์š”ํ•œ ์‹œ์ ์— ๋กœ๋“œํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

ํ”„๋กœ์ ํŠธ ๋‚ด assets ํด๋”๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ , config.json ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ˆจ๊ธฐ๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ๋“ค์„ ๋ณด๊ด€ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

config.json ํŒŒ์ผ์— ์ˆจ๊ธฐ๊ณ  ์‹ถ์€ ์„ค์ •์ด๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์ž.

{
  "clientId": {your_client_id},
  "teamId": {your_team_id},
  "keyId": {your_key_id},
  "privateKey": {your_private_key}
}

.gitignore ํŒŒ์ผ์— ์ˆจ๊ธฐ๊ณ  ์‹ถ์€ ํด๋”๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ๋ฉด, Git์— ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค. privates ํด๋” ์ „๋ถ€๋ฅผ ์ œ์™ธ ์ฒ˜๋ฆฌํ•˜์˜€๋‹ค.

assets/privates/

Flutter์—์„œ json ํŒŒ์ผ์„ ๋กœ๋“œํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

final String configJson = await rootBundle.loadString("assets/privates/config.json");
final Map<String, dynamic> data = json.decode(configJson);
print(data);

๋งˆ๋ฌด๋ฆฌ

Sign in with Apple ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์„ค์ •๋ถ€ํ„ฐ ๋กœ๊ทธ์ธ ๋ฐ ํƒˆํ‡ด์‹œ ํ† ํฐ์„ ๋ฌดํšจํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•๊นŒ์ง€ ์•Œ์•„๋ณด์•˜๋‹ค.

์ƒ๊ฐ๋ณด๋‹ค ๊ธ€์˜ ๋‚ด์šฉ์ด ๋„ˆ๋ฌด ๊ธธ์–ด์ ธ ์•„์‰ฝ๊ฒŒ๋„ ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ์• ํ”Œ ๋กœ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ ๋‹ค๋ฃจ์ง€ ๋ชปํ•˜์˜€๋Š”๋ฐ, ์•ˆ๋“œ๋กœ์ด๋“œ๋‚˜ ์›น ๊ด€๋ จ๋œ ๋ฐฉ๋ฒ•์€ ์ถ”ํ›„ ๊ธ€์„ ์ž‘์„ฑํ•  ์˜ˆ์ •์ด๋‹ค.

๊ธ€์„ ํ•œ ๋ฒˆ์— ์ž‘์„ฑํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์‹œ๊ฐ„๋‚  ๋•Œ๋งˆ๋‹ค ์กฐ๊ธˆ์”ฉ ์ž‘์„ฑํ•˜๋‹ค ๋ณด๋‹ˆ ์˜คํƒ€๋‚˜ ํ‹€๋ฆฐ ๋ถ€๋ถ„์ด ์žˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ช‡ ๋‹ฌ ๋งŒ์— ๊ธ€์„ ๊ฒŒ์‹œํ•˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ, ์•ž์œผ๋กœ๋Š” ๋‹ค์‹œ ์ฃผ๊ธฐ์ ์œผ๋กœ ๊ธ€์„ ์ž‘์„ฑํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. Flutter์™€ ๊ด€๋ จํ•˜์—ฌ ๊ถ๊ธˆํ•œ ์ ์ด๋‚˜ ์•Œ๊ณ  ์‹ถ์€ ๊ธฐ๋Šฅ์ด ์žˆ์œผ์‹œ๋ฉด ์–ธ์ œ๋“ ์ง€ ์š”์ฒญํ•ด ์ฃผ์„ธ์š”.

๊ธด ๊ธ€ ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

Sign in with Apple ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จ๋œ ๋ถ€๋ถ„์ด๋‚˜ ๊ธฐํƒ€ ๊ถ๊ธˆํ•˜์‹  ๋‚ด์šฉ์€ ๋Œ“๊ธ€ ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด ์ตœ๋Œ€ํ•œ ์‹ ์†ํ•˜๊ฒŒ ๋‹ต๋ณ€ ๋‚จ๊ธฐ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿฏ

profile
Flutter Developer

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด