āĻ…ā§āϝāĻžāĻĒāϞ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻ•āϰ⧁āύ

āĻāĻ¨ā§āĻĄ-āϟ⧁-āĻāĻ¨ā§āĻĄ OAuth 2.0 āϏāĻžāχāύ-āχāύ āĻĢā§āϞ⧋ āϚāĻžāϞāĻžāύ⧋āϰ āϜāĻ¨ā§āϝ āφāĻĒāύāĻŋ Firebase SDK āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āφāĻĒāύāĻžāϰ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āϤāĻžāĻĻ⧇āϰ Apple ID āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ Firebase-āĻāϰ āϏāĻžāĻĨ⧇ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻ•āϰāϤ⧇ āĻĻāĻŋāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤

āφāĻĒāύāĻŋ āĻļ⧁āϰ⧁ āĻ•āϰāĻžāϰ āφāϗ⧇

Apple āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āϏāĻžāχāύ āχāύ āĻ•āϰāϤ⧇, āĻĒā§āϰāĻĨāĻŽā§‡ Apple āĻāϰ āĻŦāĻŋāĻ•āĻžāĻļāĻ•āĻžāϰ⧀ āϏāĻžāχāĻŸā§‡ Apple āĻāϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰ⧁āύ, āϤāĻžāϰāĻĒāϰ āφāĻĒāύāĻžāϰ Firebase āĻĒā§āϰāĻ•āĻ˛ā§āĻĒ⧇āϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āϏāĻžāχāύ-āχāύ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀ āĻšāĻŋāϏāĻžāĻŦ⧇ Apple āϏāĻ•ā§āώāĻŽ āĻ•āϰ⧁āύ⧎

āĻ…ā§āϝāĻžāĻĒāϞ āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰ āĻĒā§āϰ⧋āĻ—ā§āϰāĻžāĻŽā§‡ āϝ⧋āĻ— āĻĻāĻŋāύ

Apple āĻāϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ Apple āĻŦāĻŋāĻ•āĻžāĻļāĻ•āĻžāϰ⧀ āĻĒā§āϰ⧋āĻ—ā§āϰāĻžāĻŽā§‡āϰ āϏāĻĻāĻ¸ā§āϝāĻĻ⧇āϰ āĻĻā§āĻŦāĻžāϰāĻž āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰāĻž āϝ⧇āϤ⧇ āĻĒāĻžāϰ⧇⧎

āĻ…ā§āϝāĻžāĻĒāϞ āĻĻāĻŋāϝāĻŧ⧇ āϏāĻžāχāύ āχāύ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰ⧁āύ

  1. Apple āĻāϰ āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰ āϏāĻžāχāĻŸā§‡āϰ āϏāĻžāĻ°ā§āϟāĻŋāĻĢāĻŋāϕ⧇āϟ, āĻļāύāĻžāĻ•ā§āϤāĻ•āĻžāϰ⧀ āĻāĻŦāĻ‚ āĻĒā§āϰ⧋āĻĢāĻžāχāϞ āĻĒ⧃āĻˇā§āĻ āĻžāϝāĻŧ āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ⧇āϰ āϜāĻ¨ā§āϝ Apple āĻĻāĻŋāϝāĻŧ⧇ āϏāĻžāχāύ āχāύ āϏāĻ•ā§āώāĻŽ āĻ•āϰ⧁āύ⧎
  2. āĻ“āϝāĻŧ⧇āĻŦ⧇āϰ āϜāĻ¨ā§āϝ Apple āĻāϰ āϏāĻžāĻĨ⧇ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āϏāĻžāχāύ āχāύ⧇āϰ āĻĒā§āϰāĻĨāĻŽ āĻŦāĻŋāĻ­āĻžāϗ⧇ āĻŦāĻ°ā§āĻŖāĻŋāϤ āĻšāĻŋāϏāĻžāĻŦ⧇ āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ⧇āϰ āϏāĻžāĻĨ⧇ āφāĻĒāύāĻžāϰ āĻ“āϝāĻŧ⧇āĻŦāϏāĻžāχāϟ āϝ⧁āĻ•ā§āϤ āĻ•āϰ⧁āύ⧎ āĻ…āύ⧁āϰ⧋āϧ āĻ•āϰāĻž āĻšāϞ⧇, āĻāĻ•āϟāĻŋ āϰāĻŋāϟāĻžāĻ°ā§āύ āχāωāφāϰāĻāϞ āĻšāĻŋāϏāĻžāĻŦ⧇ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ URL āύāĻŋāĻŦāĻ¨ā§āϧāύ āĻ•āϰ⧁āύ:
    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
    āφāĻĒāύāĻŋ Firebase āĻ•āύāϏ⧋āϞ āϏ⧇āϟāĻŋāĻ‚āϏ āĻĒ⧃āĻˇā§āĻ āĻžāϝāĻŧ āφāĻĒāύāĻžāϰ Firebase āĻĒā§āϰāĻ•āĻ˛ā§āĻĒ āφāχāĻĄāĻŋ āĻĒ⧇āϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤ āφāĻĒāύāĻžāϰ āĻšāϝāĻŧ⧇ āϗ⧇āϞ⧇, āφāĻĒāύāĻžāϰ āύāϤ⧁āύ āĻĒāϰāĻŋāώ⧇āĻŦāĻž āφāχāĻĄāĻŋ āύ⧋āϟ āĻ•āϰ⧁āύ, āϝāĻž āφāĻĒāύāĻžāϕ⧇ āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻŦāĻŋāĻ­āĻžāϗ⧇ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āĻšāĻŦ⧇⧎
  3. āĻ…ā§āϝāĻžāĻĒāϞ āĻŦā§āϝāĻ•ā§āϤāĻŋāĻ—āϤ āϕ⧀ āĻĻāĻŋāϝāĻŧ⧇ āĻāĻ•āϟāĻŋ āϏāĻžāχāύ āχāύ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āύ āĨ¤ āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻŦāĻŋāĻ­āĻžāϗ⧇ āφāĻĒāύāĻžāϰ āύāϤ⧁āύ āĻŦā§āϝāĻ•ā§āϤāĻŋāĻ—āϤ āϕ⧀ āĻāĻŦāĻ‚ āϕ⧀ āφāχāĻĄāĻŋāϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āĻšāĻŦ⧇⧎
  4. āφāĻĒāύāĻŋ āϝāĻĻāĻŋ Firebase Authentication āϕ⧋āύ⧋ āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇āύ āϝāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āχāĻŽā§‡āϞ āĻĒāĻžāĻ āĻžāϝāĻŧ, āϝāĻžāϰ āĻŽāĻ§ā§āϝ⧇ āχāĻŽā§‡āϞ āϞāĻŋāĻ™ā§āĻ• āϏāĻžāχāύ-āχāύ, āχāĻŽā§‡āϞ āĻ āĻŋāĻ•āĻžāύāĻž āϝāĻžāϚāĻžāχāĻ•āϰāĻŖ, āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻĒā§āϰāĻ¤ā§āϝāĻžāĻšāĻžāϰ, āĻāĻŦāĻ‚ āĻ…āĻ¨ā§āϝāĻžāĻ¨ā§āϝ āϏāĻš, Apple āĻĒā§āϰāĻžāχāϭ⧇āϟ āχāĻŽā§‡āϞ āϰāĻŋāϞ⧇ āĻĒāϰāĻŋāώ⧇āĻŦāĻž āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰ⧁āύ āĻāĻŦāĻ‚ noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (āĻŦāĻž āφāĻĒāύāĻžāϰ āĻ•āĻžāĻ¸ā§āϟāĻŽāĻžāχāϜāĻĄ āχāĻŽā§‡āϞ āĻŸā§‡āĻŽāĻĒā§āϞ⧇āϟ āĻĻā§āĻŦāĻžāϰāĻž āĻ…ā§āϝāĻžāĻĒāϞ āχāĻŽā§‡āϞ Firebase Authentication āĻĒāĻžāĻ āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ āĻ…ā§āϝāĻžāĻĒāϞ āĻŦā§āϝāĻ•ā§āϤāĻŋāĻ—āϤ āχāĻŽā§‡āϞ āϰāĻŋāϞ⧇ āĻĒāϰāĻŋāώ⧇āĻŦāĻž āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰ⧁āύ) āĻŦ⧇āύāĻžāĻŽā§€ āĻ…ā§āϝāĻžāĻĒāϞ āχāĻŽā§‡āϞ āĻ āĻŋāĻ•āĻžāύāĻžāϝāĻŧ.

āĻāĻ•āϟāĻŋ āϏāĻžāχāύ-āχāύ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀ āĻšāĻŋāϏāĻžāĻŦ⧇ Apple āϏāĻ•ā§āώāĻŽ āĻ•āϰ⧁āύ⧎

  1. āφāĻĒāύāĻžāϰ Apple āĻĒā§āϰāĻ•āĻ˛ā§āĻĒ⧇ Firebase āϝ⧋āĻ— āĻ•āϰ⧁āύ āĨ¤ āφāĻĒāύāĻŋ Firebase āĻ•āύāϏ⧋āϞ⧇ āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ āϏ⧇āϟ āφāĻĒ āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ⧇āϰ āĻŦāĻžāĻ¨ā§āĻĄā§‡āϞ āφāχāĻĄāĻŋ āύāĻŋāĻŦāĻ¨ā§āϧāύ āĻ•āϰāϤ⧇ āϭ⧁āϞāĻŦ⧇āύ āύāĻžāĨ¤
  2. Firebase āĻ•āύāϏ⧋āϞ⧇ , Auth āĻŦāĻŋāĻ­āĻžāĻ—āϟāĻŋ āϖ⧁āϞ⧁āύāĨ¤ āϏāĻžāχāύ āχāύ āĻĒāĻĻā§āϧāϤāĻŋ āĻŸā§āϝāĻžāĻŦ⧇, āĻ…ā§āϝāĻžāĻĒāϞ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀ āϏāĻ•ā§āώāĻŽ āĻ•āϰ⧁āύāĨ¤ āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āϤ⧀ āĻŦāĻŋāĻ­āĻžāϗ⧇ āφāĻĒāύāĻŋ āϝ⧇ āĻĒāϰāĻŋāώ⧇āĻŦāĻž āφāχāĻĄāĻŋ āϤ⧈āϰāĻŋ āĻ•āϰ⧇āϛ⧇āύ āϤāĻž āωāĻ˛ā§āϞ⧇āĻ– āĻ•āϰ⧁āύāĨ¤ āĻāĻ›āĻžāĻĄāĻŧāĻžāĻ“, OAuth āϕ⧋āĻĄ āĻĢā§āϞ⧋ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ āĻŦāĻŋāĻ­āĻžāϗ⧇ , āφāĻĒāύāĻžāϰ Apple āϟāĻŋāĻŽ āφāχāĻĄāĻŋ āĻāĻŦāĻ‚ āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āϤ⧀ āĻŦāĻŋāĻ­āĻžāϗ⧇ āφāĻĒāύāĻžāϰ āϤ⧈āϰāĻŋ āĻ•āϰāĻž āĻŦā§āϝāĻ•ā§āϤāĻŋāĻ—āϤ āϕ⧀ āĻāĻŦāĻ‚ āϕ⧀ āφāχāĻĄāĻŋ āωāĻ˛ā§āϞ⧇āĻ– āĻ•āϰ⧁āύāĨ¤

āĻ…ā§āϝāĻžāĻĒāϞ āĻŦ⧇āύāĻžāĻŽā§€ āĻĄā§‡āϟāĻž āĻĒā§āϰāϝāĻŧā§‹āϜāύ⧀āϝāĻŧāϤāĻž āĻŽā§‡āύ⧇ āϚāϞ⧁āύ

āĻ…ā§āϝāĻžāĻĒāϞ⧇āϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āϏāĻžāχāύ āχāύ āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ āϤāĻžāĻĻ⧇āϰ āχāĻŽā§‡āϞ āĻ āĻŋāĻ•āĻžāύāĻž āϏāĻš āϤāĻžāĻĻ⧇āϰ āĻĄā§‡āϟāĻž āĻŦ⧇āύāĻžāĻŽā§€ āĻ•āϰāĻžāϰ āĻŦāĻŋāĻ•āĻ˛ā§āĻĒ āĻĻ⧇āϝāĻŧ⧎ āϝ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰāĻž āĻāχ āĻŦāĻŋāĻ•āĻ˛ā§āĻĒāϟāĻŋ āĻŦ⧇āϛ⧇ āύ⧇āύ āϤāĻžāĻĻ⧇āϰ āĻ•āĻžāϛ⧇ privaterelay.appleid.com āĻĄā§‹āĻŽā§‡āύ⧇āϰ āχāĻŽā§‡āϞ āĻ āĻŋāĻ•āĻžāύāĻž āϰāϝāĻŧ⧇āϛ⧇⧎ āφāĻĒāύāĻŋ āϝāĻ–āύ āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ⧇ Apple āĻāϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇āύ, āϤāĻ–āύ āφāĻĒāύāĻžāϕ⧇ āĻ…āĻŦāĻļā§āϝāχ āĻāχ āĻŦ⧇āύāĻžāĻŽā§€ Apple ID āϏāĻ‚āĻ•ā§āϰāĻžāĻ¨ā§āϤ āϝ⧇āϕ⧋āύ āĻĒā§āϰāϝ⧋āĻœā§āϝ āĻŦāĻŋāĻ•āĻžāĻļāĻ•āĻžāϰ⧀ āύ⧀āϤāĻŋ āĻŦāĻž Apple āĻĨ⧇āϕ⧇ āĻļāĻ°ā§āϤāĻžāĻŦāϞ⧀ āĻŽā§‡āύ⧇ āϚāϞāϤ⧇ āĻšāĻŦ⧇āĨ¤

āφāĻĒāύāĻŋ āĻāĻ•āϟāĻŋ āĻŦ⧇āύāĻžāĻŽā§€ āĻ…ā§āϝāĻžāĻĒāϞ āφāχāĻĄāĻŋāϰ āϏāĻžāĻĨ⧇ āϏāϰāĻžāϏāϰāĻŋ āϏāύāĻžāĻ•ā§āϤāĻ•āĻžāϰ⧀ āĻŦā§āϝāĻ•ā§āϤāĻŋāĻ—āϤ āϤāĻĨā§āϝ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻ•āϰāĻžāϰ āφāϗ⧇ āϝ⧇āϕ⧋āύ āĻĒā§āϰāϝāĻŧā§‹āϜāύ⧀āϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āϏāĻŽā§āĻŽāϤāĻŋ āĻĒā§āϰāĻžāĻĒā§āϤ āĻ•āϰāĻž āĻāϰ āĻŽāĻ§ā§āϝ⧇ āϰāϝāĻŧ⧇āϛ⧇āĨ¤ āĻĢāĻžāϝāĻŧāĻžāϰāĻŦ⧇āϏ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ, āĻāϤ⧇ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻ•ā§āϰāĻŋāϝāĻŧāĻžāϗ⧁āϞāĻŋ āĻ…āĻ¨ā§āϤāĻ°ā§āϭ⧁āĻ•ā§āϤ āĻĨāĻžāĻ•āϤ⧇ āĻĒāĻžāϰ⧇:

  • āĻāĻ•āϟāĻŋ āĻŦ⧇āύāĻžāĻŽā§€ āĻ…ā§āϝāĻžāĻĒāϞ āφāχāĻĄāĻŋ āĻŦāĻž āĻŦāĻŋāĻĒāϰ⧀āϤ⧇ āĻāĻ•āϟāĻŋ āχāĻŽā§‡āϞ āĻ āĻŋāĻ•āĻžāύāĻž āϞāĻŋāĻ™ā§āĻ• āĻ•āϰ⧁āύ.
  • āĻāĻ•āϟāĻŋ āĻŦ⧇āύāĻžāĻŽā§€ āĻ…ā§āϝāĻžāĻĒāϞ āφāχāĻĄāĻŋāϤ⧇ āĻāĻ•āϟāĻŋ āĻĢā§‹āύ āύāĻŽā§āĻŦāϰ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰ⧁āύ āĻŦāĻž āĻāϰ āĻŦāĻŋāĻĒāϰ⧀āϤ⧇
  • āĻāĻ•āϟāĻŋ āĻŦ⧇āύāĻžāĻŽā§€ āϏāĻžāĻŽāĻžāϜāĻŋāĻ• āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰ (āĻĢ⧇āϏāĻŦ⧁āĻ•, āϗ⧁āĻ—āϞ, āχāĻ¤ā§āϝāĻžāĻĻāĻŋ) āĻāĻ•āϟāĻŋ āĻŦ⧇āύāĻžāĻŽā§€ āĻ…ā§āϝāĻžāĻĒāϞ āφāχāĻĄāĻŋāϤ⧇ āĻŦāĻž āĻāϰ āĻŦāĻŋāĻĒāϰ⧀āϤ⧇ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰ⧁āύ⧎

āωāĻĒāϰ⧇āϰ āϤāĻžāϞāĻŋāĻ•āĻžāϟāĻŋ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āύāϝāĻŧāĨ¤ āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ āĻ…ā§āϝāĻžāĻĒāϞ⧇āϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ⧀āϝāĻŧāϤāĻž āĻĒā§‚āϰāĻŖ āĻ•āϰāϛ⧇ āϤāĻž āύāĻŋāĻļā§āϚāĻŋāϤ āĻ•āϰāϤ⧇ āφāĻĒāύāĻžāϰ āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡āϰ āϏāĻĻāĻ¸ā§āϝāĻĒāĻĻ āĻŦāĻŋāĻ­āĻžāϗ⧇ āĻ…ā§āϝāĻžāĻĒāϞ āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰ āĻĒā§āϰ⧋āĻ—ā§āϰāĻžāĻŽ āϞāĻžāχāϏ⧇āĻ¨ā§āϏ āϚ⧁āĻ•ā§āϤāĻŋ āĻĒāĻĄāĻŧ⧁āύāĨ¤

Apple āĻāϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ āĻ•āϰ⧁āύ āĻāĻŦāĻ‚ Firebase āĻāϰ āϏāĻžāĻĨ⧇ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻ•āϰ⧁āύ⧎

āĻāĻ•āϟāĻŋ Apple āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡āϰ āϏāĻžāĻĨ⧇ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻ•āϰāϤ⧇, āĻĒā§āϰāĻĨāĻŽā§‡ Apple āĻāϰ AuthenticationServices āĻĢā§āϰ⧇āĻŽāĻ“āϝāĻŧāĻžāĻ°ā§āĻ• āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϕ⧇ āϤāĻžāĻĻ⧇āϰ Apple āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡ āϏāĻžāχāύ āχāύ āĻ•āϰ⧁āύ āĻāĻŦāĻ‚ āϤāĻžāϰāĻĒāϰ⧇ āĻāĻ•āϟāĻŋ Firebase AuthCredential āĻ…āĻŦāĻœā§‡āĻ•ā§āϟ āϤ⧈āϰāĻŋ āĻ•āϰāϤ⧇ Apple āĻāϰ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āĻĨ⧇āϕ⧇ āφāχāĻĄāĻŋ āĻŸā§‹āϕ⧇āύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύ:

  1. āĻĒā§āϰāϤāĻŋāϟāĻŋ āϏāĻžāχāύ-āχāύ āĻ…āύ⧁āϰ⧋āϧ⧇āϰ āϜāĻ¨ā§āϝ, āĻāĻ•āϟāĻŋ āĻāϞ⧋āĻŽā§‡āϞ⧋ āĻ¸ā§āĻŸā§āϰāĻŋāĻ‚ āϤ⧈āϰāĻŋ āĻ•āϰ⧁āĻ¨â€”āĻāĻ•āϟāĻŋ "āύāύāϏ"—āϝāĻž āφāĻĒāύāĻŋ āύāĻŋāĻļā§āϚāĻŋāϤ āĻ•āϰāϤ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻŦ⧇āύ āϝ⧇ āφāĻĒāύāĻŋ āϝ⧇ āφāχāĻĄāĻŋ āĻŸā§‹āϕ⧇āύāϟāĻŋ āĻĒ⧇āϝāĻŧ⧇āϛ⧇āύ āϤāĻž āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ⧇āϰ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻ…āύ⧁āϰ⧋āϧ⧇āϰ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āĻšāĻŋāϏāĻžāĻŦ⧇ āĻŦāĻŋāĻļ⧇āώāĻ­āĻžāĻŦ⧇ āĻŽāĻžā§āϜ⧁āϰ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇āĨ¤ āϰāĻŋāĻĒā§āϞ⧇ āφāĻ•ā§āϰāĻŽāĻŖ āĻĒā§āϰāϤāĻŋāϰ⧋āϧ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻāχ āĻĒāĻĻāĻ•ā§āώ⧇āĻĒāϟāĻŋ āϗ⧁āϰ⧁āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖāĨ¤

    āφāĻĒāύāĻŋ āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āωāĻĻāĻžāĻšāϰāϪ⧇āϰ āĻŽāϤ⧋ SecRandomCopyBytes(_:_:_) āĻĻāĻŋāϝāĻŧ⧇ āĻāĻ•āϟāĻŋ āĻ•ā§āϰāĻŋāĻĒā§āĻŸā§‹āĻ—ā§āϰāĻžāĻĢāĻŋāĻ•āĻ­āĻžāĻŦ⧇ āϏ⧁āϰāĻ•ā§āώāĻŋāϤ āύāĻ¨ā§āϏ āϤ⧈āϰāĻŋ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύ:

    āϏ⧁āχāĻĢāϟ

    private func randomNonceString(length: Int = 32) -> String {
      precondition(length > 0)
      var randomBytes = [UInt8](repeating: 0, count: length)
      let errorCode = SecRandomCopyBytes(kSecRandomDefault, randomBytes.count, &randomBytes)
      if errorCode != errSecSuccess {
        fatalError(
          "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)"
        )
      }
    
      let charset: [Character] =
        Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
    
      let nonce = randomBytes.map { byte in
        // Pick a random character from the set, wrapping around if needed.
        charset[Int(byte) % charset.count]
      }
    
      return String(nonce)
    }
    
        

    āωāĻĻā§āĻĻ⧇āĻļā§āϝ-C

    // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
    - (NSString *)randomNonce:(NSInteger)length {
      NSAssert(length > 0, @"Expected nonce to have positive length");
      NSString *characterSet = @"0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._";
      NSMutableString *result = [NSMutableString string];
      NSInteger remainingLength = length;
    
      while (remainingLength > 0) {
        NSMutableArray *randoms = [NSMutableArray arrayWithCapacity:16];
        for (NSInteger i = 0; i < 16; i++) {
          uint8_t random = 0;
          int errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random);
          NSAssert(errorCode == errSecSuccess, @"Unable to generate nonce: OSStatus %i", errorCode);
    
          [randoms addObject:@(random)];
        }
    
        for (NSNumber *random in randoms) {
          if (remainingLength == 0) {
            break;
          }
    
          if (random.unsignedIntValue < characterSet.length) {
            unichar character = [characterSet characterAtIndex:random.unsignedIntValue];
            [result appendFormat:@"%C", character];
            remainingLength--;
          }
        }
      }
    
      return [result copy];
    }
        

    āφāĻĒāύāĻŋ āφāĻĒāύāĻžāϰ āϏāĻžāχāύ-āχāύ āĻ…āύ⧁āϰ⧋āϧ⧇āϰ āϏāĻžāĻĨ⧇ āύāύāϏ⧇āϰ SHA256 āĻšā§āϝāĻžāĻļ āĻĒāĻžāĻ āĻžāĻŦ⧇āύ, āϝāĻž Apple āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻžāϝāĻŧ āĻ…āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāĻŋāϤ āĻĒāĻžāϏ āĻ•āϰāĻŦ⧇āĨ¤ Firebase āφāϏāϞ āύāĻ¨ā§āϏ āĻšā§āϝāĻžāĻļ āĻ•āϰ⧇ āĻāĻŦāĻ‚ Apple āĻĻā§āĻŦāĻžāϰāĻž āĻĒāĻžāϏ āĻ•āϰāĻž āĻŽāĻžāύ⧇āϰ āϏāĻžāĻĨ⧇ āϤ⧁āϞāύāĻž āĻ•āϰ⧇ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āϝāĻžāϚāĻžāχ āĻ•āϰ⧇āĨ¤

    āϏ⧁āχāĻĢāϟ

    @available(iOS 13, *)
    private func sha256(_ input: String) -> String {
      let inputData = Data(input.utf8)
      let hashedData = SHA256.hash(data: inputData)
      let hashString = hashedData.compactMap {
        String(format: "%02x", $0)
      }.joined()
    
      return hashString
    }
    
        

    āωāĻĻā§āĻĻ⧇āĻļā§āϝ-C

    - (NSString *)stringBySha256HashingString:(NSString *)input {
      const char *string = [input UTF8String];
      unsigned char result[CC_SHA256_DIGEST_LENGTH];
      CC_SHA256(string, (CC_LONG)strlen(string), result);
    
      NSMutableString *hashed = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
      for (NSInteger i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {
        [hashed appendFormat:@"%02x", result[i]];
      }
      return hashed;
    }
        
  2. Apple-āĻāϰ āϏāĻžāχāύ-āχāύ āĻĢā§āϞ⧋ āĻļ⧁āϰ⧁ āĻ•āϰ⧁āύ, āφāĻĒāύāĻžāϰ āĻ…āύ⧁āϰ⧋āϧ⧇ āύāύāϏ⧇āϰ SHA256 āĻšā§āϝāĻžāĻļ āĻāĻŦāĻ‚ āĻ…ā§āϝāĻžāĻĒāϞ⧇āϰ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻ•āϰāĻŦ⧇ āĻāĻŽāύ āĻĒā§āϰāϤāĻŋāύāĻŋāϧāĻŋ āĻ•ā§āϞāĻžāϏ āϏāĻš (āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āϧāĻžāĻĒāϟāĻŋ āĻĻ⧇āϖ⧁āύ):

    āϏ⧁āχāĻĢāϟ

    import CryptoKit
    
    // Unhashed nonce.
    fileprivate var currentNonce: String?
    
    @available(iOS 13, *)
    func startSignInWithAppleFlow() {
      let nonce = randomNonceString()
      currentNonce = nonce
      let appleIDProvider = ASAuthorizationAppleIDProvider()
      let request = appleIDProvider.createRequest()
      request.requestedScopes = [.fullName, .email]
      request.nonce = sha256(nonce)
    
      let authorizationController = ASAuthorizationController(authorizationRequests: [request])
      authorizationController.delegate = self
      authorizationController.presentationContextProvider = self
      authorizationController.performRequests()
    }
    

    āωāĻĻā§āĻĻ⧇āĻļā§āϝ-C

    @import CommonCrypto;
    
    - (void)startSignInWithAppleFlow {
      NSString *nonce = [self randomNonce:32];
      self.currentNonce = nonce;
      ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
      ASAuthorizationAppleIDRequest *request = [appleIDProvider createRequest];
      request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
      request.nonce = [self stringBySha256HashingString:nonce];
    
      ASAuthorizationController *authorizationController =
          [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
      authorizationController.delegate = self;
      authorizationController.presentationContextProvider = self;
      [authorizationController performRequests];
    }
    
  3. ASAuthorizationControllerDelegate āφāĻĒāύāĻžāϰ āĻŦāĻžāĻ¸ā§āϤāĻŦāĻžāϝāĻŧāύ⧇ āĻ…ā§āϝāĻžāĻĒāϞ⧇āϰ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻ•āϰ⧁āύāĨ¤ āϏāĻžāχāύ-āχāύ āϏāĻĢāϞ āĻšāϞ⧇, āĻĢāĻžāϝāĻŧāĻžāϰāĻŦ⧇āϏ⧇āϰ āϏāĻžāĻĨ⧇ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāϪ⧇āϰ āϜāĻ¨ā§āϝ āφāύāĻšā§āϝāĻžāĻļāĻĄ āύāĻ¨ā§āϏ āϏāĻš āĻ…ā§āϝāĻžāĻĒāϞ⧇āϰ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āĻĨ⧇āϕ⧇ āφāχāĻĄāĻŋ āĻŸā§‹āϕ⧇āύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύ:

    āϏ⧁āχāĻĢāϟ

    @available(iOS 13.0, *)
    extension MainViewController: ASAuthorizationControllerDelegate {
    
      func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
          guard let nonce = currentNonce else {
            fatalError("Invalid state: A login callback was received, but no login request was sent.")
          }
          guard let appleIDToken = appleIDCredential.identityToken else {
            print("Unable to fetch identity token")
            return
          }
          guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
            print("Unable to serialize token string from data: \(appleIDToken.debugDescription)")
            return
          }
          // Initialize a Firebase credential, including the user's full name.
          let credential = OAuthProvider.appleCredential(withIDToken: idTokenString,
                                                            rawNonce: nonce,
                                                            fullName: appleIDCredential.fullName)
          // Sign in with Firebase.
          Auth.auth().signIn(with: credential) { (authResult, error) in
            if error {
              // Error. If error.code == .MissingOrInvalidNonce, make sure
              // you're sending the SHA256-hashed nonce as a hex string with
              // your request to Apple.
              print(error.localizedDescription)
              return
            }
            // User is signed in to Firebase with Apple.
            // ...
          }
        }
      }
    
      func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // Handle error.
        print("Sign in with Apple errored: \(error)")
      }
    
    }
    

    āωāĻĻā§āĻĻ⧇āĻļā§āϝ-C

    - (void)authorizationController:(ASAuthorizationController *)controller
       didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
      if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
        ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
        NSString *rawNonce = self.currentNonce;
        NSAssert(rawNonce != nil, @"Invalid state: A login callback was received, but no login request was sent.");
    
        if (appleIDCredential.identityToken == nil) {
          NSLog(@"Unable to fetch identity token.");
          return;
        }
    
        NSString *idToken = [[NSString alloc] initWithData:appleIDCredential.identityToken
                                                  encoding:NSUTF8StringEncoding];
        if (idToken == nil) {
          NSLog(@"Unable to serialize id token from data: %@", appleIDCredential.identityToken);
        }
    
        // Initialize a Firebase credential, including the user's full name.
        FIROAuthCredential *credential = [FIROAuthProvider appleCredentialWithIDToken:IDToken
                                                                             rawNonce:self.appleRawNonce
                                                                             fullName:appleIDCredential.fullName];
    
        // Sign in with Firebase.
        [[FIRAuth auth] signInWithCredential:credential
                                  completion:^(FIRAuthDataResult * _Nullable authResult,
                                               NSError * _Nullable error) {
          if (error != nil) {
            // Error. If error.code == FIRAuthErrorCodeMissingOrInvalidNonce,
            // make sure you're sending the SHA256-hashed nonce as a hex string
            // with your request to Apple.
            return;
          }
          // Sign-in succeeded!
        }];
      }
    }
    
    - (void)authorizationController:(ASAuthorizationController *)controller
               didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0)) {
      NSLog(@"Sign in with Apple errored: %@", error);
    }
    

Firebase Auth āĻĻā§āĻŦāĻžāϰāĻž āϏāĻŽāĻ°ā§āĻĨāĻŋāϤ āĻ…āĻ¨ā§āϝāĻžāĻ¨ā§āϝ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āĻĨ⧇āϕ⧇ āĻ­āĻŋāĻ¨ā§āύ, Apple āĻāĻ•āϟāĻŋ āĻĢāĻŸā§‹ URL āĻĒā§āϰāĻĻāĻžāύ āĻ•āϰ⧇ āύāĻžāĨ¤

āĻāĻ›āĻžāĻĄāĻŧāĻžāĻ“, āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āϝāĻ–āύ āĻ…ā§āϝāĻžāĻĒ⧇āϰ āϏāĻžāĻĨ⧇ āϤāĻžāĻĻ⧇āϰ āχāĻŽā§‡āϞ āĻļ⧇āϝāĻŧāĻžāϰ āύāĻž āĻ•āϰāĻž āĻŦ⧇āϛ⧇ āύ⧇āϝāĻŧ, āϤāĻ–āύ āĻ…ā§āϝāĻžāĻĒāϞ āϏ⧇āχ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āĻ…āύāĻ¨ā§āϝ āχāĻŽā§‡āϞ āĻ āĻŋāĻ•āĻžāύāĻžāϰ āĻŦā§āϝāĻŦāĻ¸ā§āĻĨāĻž āĻ•āϰ⧇ (āĻĢāĻ°ā§āĻŽ xyz@privaterelay.appleid.com ), āϝāĻž āĻāϟāĻŋ āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ⧇āϰ āϏāĻžāĻĨ⧇ āĻļ⧇āϝāĻŧāĻžāϰ āĻ•āϰ⧇āĨ¤ āφāĻĒāύāĻŋ āϝāĻĻāĻŋ āĻŦā§āϝāĻ•ā§āϤāĻŋāĻ—āϤ āχāĻŽā§‡āϞ āϰāĻŋāϞ⧇ āĻĒāϰāĻŋāώ⧇āĻŦāĻž āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰ⧇āύ, āĻ…ā§āϝāĻžāĻĒāϞ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āφāϏāϞ āχāĻŽā§‡āϞ āĻ āĻŋāĻ•āĻžāύāĻžāϝāĻŧ āĻŦ⧇āύāĻžāĻŽā§€ āĻ āĻŋāĻ•āĻžāύāĻžāϝāĻŧ āĻĒāĻžāĻ āĻžāύ⧋ āχāĻŽā§‡āϞāϗ⧁āϞāĻŋ āĻĢāϰāĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āĻ•āϰ⧇āĨ¤

āĻĒ⧁āύāϰāĻžāϝāĻŧ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻāĻŦāĻ‚ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āϞāĻŋāĻ™ā§āĻ•āĻŋāĻ‚

āĻāĻ•āχ āĻĒā§āϝāĻžāϟāĻžāĻ°ā§āύāϟāĻŋ reauthenticateWithCredential() āĻāϰ āϏāĻžāĻĨ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āϝ⧇āϤ⧇ āĻĒāĻžāϰ⧇, āϝāĻž āφāĻĒāύāĻŋ āϏāĻžāĻŽā§āĻĒā§āϰāϤāĻŋāĻ• āϏāĻžāχāύ-āχāύ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āĻāĻŽāύ āϏāĻ‚āĻŦ⧇āĻĻāύāĻļā§€āϞ āĻ…āĻĒāĻžāϰ⧇āĻļāύāϗ⧁āϞāĻŋāϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āύāϤ⧁āύ āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰ āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰāϤ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύ:

āϏ⧁āχāĻĢāϟ

// Initialize a fresh Apple credential with Firebase.
let credential = OAuthProvider.credential(
  withProviderID: "apple.com",
  IDToken: appleIdToken,
  rawNonce: rawNonce
)
// Reauthenticate current Apple user with fresh Apple credential.
Auth.auth().currentUser.reauthenticate(with: credential) { (authResult, error) in
  guard error != nil else { return }
  // Apple user successfully re-authenticated.
  // ...
}

āωāĻĻā§āĻĻ⧇āĻļā§āϝ-C

FIRAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com",
                                                                   IDToken:appleIdToken,
                                                                  rawNonce:rawNonce];
[[FIRAuth auth].currentUser
    reauthenticateWithCredential:credential
                      completion:^(FIRAuthDataResult * _Nullable authResult,
                                   NSError * _Nullable error) {
  if (error) {
    // Handle error.
  }
  // Apple user successfully re-authenticated.
  // ...
}];

āĻāĻŦāĻ‚, āφāĻĒāύāĻŋ āĻŦāĻŋāĻĻā§āϝāĻŽāĻžāύ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āύ āĻĒāϰāĻŋāϚāϝāĻŧ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀āϕ⧇ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰāϤ⧇ linkWithCredential() āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤

āĻŽāύ⧇ āϰāĻžāĻ–āĻŦ⧇āύ āϝ⧇ āĻ…ā§āϝāĻžāĻĒāϞ āφāĻĒāύāĻžāϕ⧇ āϤāĻžāĻĻ⧇āϰ āĻ…ā§āϝāĻžāĻĒāϞ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟāϗ⧁āϞāĻŋāϕ⧇ āĻ…āĻ¨ā§āϝ āĻĄā§‡āϟāĻžāϰ āϏāĻžāĻĨ⧇ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰāĻžāϰ āφāϗ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āĻ•āĻžāĻ› āĻĨ⧇āϕ⧇ āĻ¸ā§āĻĒāĻˇā§āϟ āϏāĻŽā§āĻŽāϤāĻŋ āύāĻŋāϤ⧇ āĻšāĻŦ⧇āĨ¤

Apple āĻāϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ āĻ•āϰāϞ⧇ āφāĻĒāύāĻŋ āĻāĻ•āϟāĻŋ āĻŦāĻŋāĻĻā§āϝāĻŽāĻžāύ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡āϰ āϏāĻžāĻĨ⧇ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻāĻ•āϟāĻŋ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰ āĻĒ⧁āύāϰāĻžāϝāĻŧ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āύ āύāĻžā§ˇ āφāĻĒāύāĻŋ āϝāĻĻāĻŋ āĻ…āĻ¨ā§āϝ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡ Apple āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰ⧇āϰ āϏāĻžāĻĨ⧇ āĻāĻ•āϟāĻŋ āϏāĻžāχāύ āχāύ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰāϤ⧇ āϚāĻžāύ, āϤāĻžāĻšāϞ⧇ āφāĻĒāύāĻžāϕ⧇ āĻĒā§āϰāĻĨāĻŽā§‡ Apple āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰ⧇āϰ āϏāĻžāĻĨ⧇ āĻĒ⧁āϰāĻžāύ⧋ āϏāĻžāχāύ āχāύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟāϗ⧁āϞāĻŋ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰāĻžāϰ āĻšā§‡āĻˇā§āϟāĻž āĻ•āϰāϤ⧇ āĻšāĻŦ⧇ āĻāĻŦāĻ‚ āϤāĻžāϰāĻĒāϰ⧇ āĻāĻ•āϟāĻŋ āύāϤ⧁āύ āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰ āϖ⧁āρāĻœā§‡ āĻĒ⧇āϤ⧇ āĻ¤ā§āϰ⧁āϟāĻŋāϟāĻŋ āĻĒāϰ⧀āĻ•ā§āώāĻž āĻ•āϰāϤ⧇ āĻšāĻŦ⧇⧎ āύāϤ⧁āύ āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰāϟāĻŋ āĻ¤ā§āϰ⧁āϟāĻŋāϰ userInfo āĻ…āĻ­āĻŋāϧāĻžāύ⧇ āĻ…āĻŦāĻ¸ā§āĻĨāĻŋāϤ āĻšāĻŦ⧇ āĻāĻŦāĻ‚ AuthErrorUserInfoUpdatedCredentialKey āϕ⧀ āĻāϰ āĻŽāĻžāĻ§ā§āϝāĻŽā§‡ āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻ•āϰāĻž āϝ⧇āϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

āωāĻĻāĻžāĻšāϰāĻŖāĻ¸ā§āĻŦāϰ⧂āĻĒ, āĻŦāĻ°ā§āϤāĻŽāĻžāύ āĻĢāĻžāϝāĻŧāĻžāϰāĻŦ⧇āϏ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡āϰ āϏāĻžāĻĨ⧇ āĻāĻ•āϟāĻŋ Facebook āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰāϤ⧇, āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϕ⧇ Facebook-āĻ āϏāĻžāχāύ āχāύ āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ āφāĻĒāύāĻŋ āϝ⧇ āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻŸā§‹āϕ⧇āύ āĻĒ⧇āϝāĻŧ⧇āϛ⧇āύ āϤāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύ:

āϏ⧁āχāĻĢāϟ

// Initialize a Facebook credential with Firebase.
let credential = FacebookAuthProvider.credential(
  withAccessToken: AccessToken.current!.tokenString
)
// Assuming the current user is an Apple user linking a Facebook provider.
Auth.auth().currentUser.link(with: credential) { (authResult, error) in
  // Facebook credential is linked to the current Apple user.
  // The user can now sign in with Facebook or Apple to the same Firebase
  // account.
  // ...
}

āωāĻĻā§āĻĻ⧇āĻļā§āϝ-C

// Initialize a Facebook credential with Firebase.
FacebookAuthCredential *credential = [FIRFacebookAuthProvider credentialWithAccessToken:accessToken];
// Assuming the current user is an Apple user linking a Facebook provider.
[FIRAuth.auth linkWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
  // Facebook credential is linked to the current Apple user.
  // The user can now sign in with Facebook or Apple to the same Firebase
  // account.
  // ...
}];

āĻŸā§‹āϕ⧇āύ āĻĒā§āϰāĻ¤ā§āϝāĻžāĻšāĻžāϰ

āĻ…ā§āϝāĻžāĻĒāϞ⧇āϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āϝ⧇ āĻ…ā§āϝāĻžāĻĒāϗ⧁āϞāĻŋ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āϤ⧈āϰāĻŋāϕ⧇ āϏāĻŽāĻ°ā§āĻĨāύ āĻ•āϰ⧇ āϏ⧇āϗ⧁āϞāĻŋāϕ⧇ āĻ…āĻŦāĻļā§āϝāχ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āĻ…ā§āϝāĻžāĻĒ⧇āϰ āĻŽāĻ§ā§āϝ⧇ āϤāĻžāĻĻ⧇āϰ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āĻŽā§āϛ⧇ āĻĢ⧇āϞāĻž āĻļ⧁āϰ⧁ āĻ•āϰāϤ⧇ āĻĻāĻŋāϤ⧇ āĻšāĻŦ⧇, āϝ⧇āĻŽāύ āĻ…ā§āϝāĻžāĻĒ āĻ¸ā§āĻŸā§‹āϰ āĻĒāĻ°ā§āϝāĻžāϞ⧋āϚāύāĻž āύāĻŋāĻ°ā§āĻĻ⧇āĻļāĻŋāĻ•āĻžāϤ⧇ āĻŦāĻ°ā§āĻŖāĻŋāϤ āĻšāϝāĻŧ⧇āϛ⧇

āĻāχ āĻĒā§āϰāϝāĻŧā§‹āϜāύ⧀āϝāĻŧāϤāĻž āĻĒā§‚āϰāĻŖ āĻ•āϰāϤ⧇, āύāĻŋāĻŽā§āύāϞāĻŋāĻ–āĻŋāϤ āĻĒāĻĻāĻ•ā§āώ⧇āĻĒāϗ⧁āϞāĻŋ āĻŦāĻžāĻ¸ā§āϤāĻŦāĻžāϝāĻŧāύ āĻ•āϰ⧁āύ:

  1. āύāĻŋāĻļā§āϚāĻŋāϤ āĻ•āϰ⧁āύ āϝ⧇ āφāĻĒāύāĻŋ āĻ…ā§āϝāĻžāĻĒāϞ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ⧇āϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ-āĻāϰ āĻĒāϰāĻŋāώ⧇āĻŦāĻž āφāχāĻĄāĻŋ āĻāĻŦāĻ‚ OAuth āϕ⧋āĻĄ āĻĢā§āϞ⧋ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ āĻŦāĻŋāĻ­āĻžāĻ—āϟāĻŋ āĻĒā§‚āϰāĻŖ āĻ•āϰ⧇āϛ⧇āύ, āϝ⧇āĻŽāύāϟāĻŋ āĻ…ā§āϝāĻžāĻĒāϞ⧇āϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰ⧁āύ āĻŦāĻŋāĻ­āĻžāϗ⧇ āĻŦāĻ°ā§āĻŖāĻŋāϤ āĻšāϝāĻŧ⧇āϛ⧇āĨ¤

  2. āϝ⧇āĻšā§‡āϤ⧁ Firebase āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻŸā§‹āϕ⧇āύ āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰ⧇ āύāĻž āϝāĻ–āύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰāĻž āĻ…ā§āϝāĻžāĻĒāϞ⧇āϰ āϏāĻžāĻĨ⧇ āϏāĻžāχāύ āχāύ āĻ•āϰ⧇ āϤ⧈āϰāĻŋ āĻ•āϰāĻž āĻšāϝāĻŧ, āϤāĻžāχ āφāĻĒāύāĻžāϕ⧇ āĻ…āĻŦāĻļā§āϝāχ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϕ⧇ āϤāĻžāĻĻ⧇āϰ āĻŸā§‹āϕ⧇āύ āĻĒā§āϰāĻ¤ā§āϝāĻžāĻšāĻžāϰ āĻāĻŦāĻ‚ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āĻŽā§āϛ⧇ āĻĢ⧇āϞāĻžāϰ āφāϗ⧇ āφāĻŦāĻžāϰ āϏāĻžāχāύ āχāύ āĻ•āϰāϤ⧇ āĻŦāϞāϤ⧇ āĻšāĻŦ⧇āĨ¤

    āϏ⧁āχāĻĢāϟ

    private func deleteCurrentUser() {
      do {
        let nonce = try CryptoUtils.randomNonceString()
        currentNonce = nonce
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.fullName, .email]
        request.nonce = CryptoUtils.sha256(nonce)
    
        let authorizationController = ASAuthorizationController(authorizationRequests: [request])
        authorizationController.delegate = self
        authorizationController.presentationContextProvider = self
        authorizationController.performRequests()
      } catch {
        // In the unlikely case that nonce generation fails, show error view.
        displayError(error)
      }
    }
  3. ASAuthorizationAppleIDCredential āĻĨ⧇āϕ⧇ āĻ…āύ⧁āĻŽā§‹āĻĻāύ āϕ⧋āĻĄāϟāĻŋ āĻĒāĻžāύ āĻāĻŦāĻ‚ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻŸā§‹āϕ⧇āύ āĻĒā§āϰāĻ¤ā§āϝāĻžāĻšāĻžāϰ āĻ•āϰāϤ⧇ Auth.auth().revokeToken(withAuthorizationCode:) āĻ•āϞ āĻ•āϰāϤ⧇ āĻāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύāĨ¤

    āϏ⧁āχāĻĢāϟ

    func authorizationController(controller: ASAuthorizationController,
                                 didCompleteWithAuthorization authorization: ASAuthorization) {
      guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential
      else {
        print("Unable to retrieve AppleIDCredential")
        return
      }
    
      guard let _ = currentNonce else {
        fatalError("Invalid state: A login callback was received, but no login request was sent.")
      }
    
      guard let appleAuthCode = appleIDCredential.authorizationCode else {
        print("Unable to fetch authorization code")
        return
      }
    
      guard let authCodeString = String(data: appleAuthCode, encoding: .utf8) else {
        print("Unable to serialize auth code string from data: \(appleAuthCode.debugDescription)")
        return
      }
    
      Task {
        do {
          try await Auth.auth().revokeToken(withAuthorizationCode: authCodeString)
          try await user?.delete()
          self.updateUI()
        } catch {
          self.displayError(error)
        }
      }
    }
  4. āĻ…āĻŦāĻļ⧇āώ⧇, āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ (āĻāĻŦāĻ‚ āϏāĻŽāĻ¸ā§āϤ āϏāĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāϤ āĻĄā§‡āϟāĻž) āĻŽā§āϛ⧁āύ

āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻĒāĻĻāĻ•ā§āώ⧇āĻĒ

āĻāĻ•āϜāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āĻĒā§āϰāĻĨāĻŽāĻŦāĻžāϰ āϏāĻžāχāύ āχāύ āĻ•āϰāĻžāϰ āĻĒāϰ⧇, āĻāĻ•āϟāĻŋ āύāϤ⧁āύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟ āϤ⧈āϰāĻŋ āĻ•āϰāĻž āĻšāϝāĻŧ āĻāĻŦāĻ‚ āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰāϗ⧁āϞāĻŋāϰ āϏāĻžāĻĨ⧇ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰāĻž āĻšāϝāĻŧ—āĻ…āĻ°ā§āĻĨāĻžā§Ž, āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āύāĻžāĻŽ āĻāĻŦāĻ‚ āĻĒāĻžāϏāĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ, āĻĢā§‹āύ āύāĻŽā§āĻŦāϰ, āĻŦāĻž āĻĒā§āϰāĻŽāĻžāĻŖ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀āϰ āϤāĻĨā§āϝ — āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āϏāĻžāχāύ āχāύ āĻ•āϰ⧇āϛ⧇āύāĨ¤ āĻāχ āύāϤ⧁āύ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āϟāϟāĻŋ āφāĻĒāύāĻžāϰ āĻĢāĻžāϝāĻŧāĻžāϰāĻŦ⧇āϏ āĻĒā§āϰāĻ•āĻ˛ā§āĻĒ⧇āϰ āĻ…āĻ‚āĻļ āĻšāĻŋāϏāĻžāĻŦ⧇ āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇ āĻāĻŦāĻ‚ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āϕ⧀āĻ­āĻžāĻŦ⧇ āϏāĻžāχāύ āχāύ āĻ•āϰ⧁āύ āύāĻž āϕ⧇āύ, āφāĻĒāύāĻžāϰ āĻĒā§āϰāĻ•āĻ˛ā§āĻĒ⧇āϰ āĻĒā§āϰāϤāĻŋāϟāĻŋ āĻ…ā§āϝāĻžāĻĒ āϜ⧁āĻĄāĻŧ⧇ āĻāĻ•āϜāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϕ⧇ āĻļāύāĻžāĻ•ā§āϤ āĻ•āϰāϤ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āϝ⧇āϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

  • āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ⧇, āφāĻĒāύāĻŋ User āĻ…āĻŦāĻœā§‡āĻ•ā§āϟ āĻĨ⧇āϕ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻŽā§ŒāϞāĻŋāĻ• āĻĒā§āϰ⧋āĻĢāĻžāχāϞ āϤāĻĨā§āϝ āĻĒ⧇āϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āĻĒāϰāĻŋāϚāĻžāϞāύāĻž āĻĻ⧇āϖ⧁āύāĨ¤

  • āφāĻĒāύāĻžāϰ Firebase Realtime Database āĻāĻŦāĻ‚ Cloud Storage āϏ⧁āϰāĻ•ā§āώāĻž āύāĻŋāϝāĻŧāĻŽā§‡ , āφāĻĒāύāĻŋ auth āϭ⧇āϰāĻŋāϝāĻŧ⧇āĻŦāϞ āĻĨ⧇āϕ⧇ āϏāĻžāχāύ-āχāύ āĻ•āϰāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻ…āύāĻ¨ā§āϝ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āφāχāĻĄāĻŋ āĻĒ⧇āϤ⧇ āĻĒāĻžāϰ⧇āύ āĻāĻŦāĻ‚ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āϕ⧋āύ āĻĄā§‡āϟāĻž āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇ āϤāĻž āύāĻŋāϝāĻŧāĻ¨ā§āĻ¤ā§āϰāĻŖ āĻ•āϰāϤ⧇ āĻāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤

āφāĻĒāύāĻŋ āĻāĻ•āϟāĻŋ āĻŦāĻŋāĻĻā§āϝāĻŽāĻžāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰ āĻ…ā§āϝāĻžāĻ•āĻžāωāĻ¨ā§āĻŸā§‡ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀āϰ āĻļāĻ‚āϏāĻžāĻĒāĻ¤ā§āϰ āϞāĻŋāĻ™ā§āĻ• āĻ•āϰ⧇ āĻāĻ•āĻžāϧāĻŋāĻ• āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻĒā§āϰāĻĻāĻžāύāĻ•āĻžāϰ⧀ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āĻĻ⧇āϰ āφāĻĒāύāĻžāϰ āĻ…ā§āϝāĻžāĻĒ⧇ āϏāĻžāχāύ āχāύ āĻ•āϰāĻžāϰ āĻ…āύ⧁āĻŽāϤāĻŋ āĻĻāĻŋāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤

āĻāĻ•āϜāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϕ⧇ āϏāĻžāχāύ āφāωāϟ āĻ•āϰāϤ⧇, signOut:

āϏ⧁āχāĻĢāϟ

let firebaseAuth = Auth.auth()
do {
  try firebaseAuth.signOut()
} catch let signOutError as NSError {
  print("Error signing out: %@", signOutError)
}

āωāĻĻā§āĻĻ⧇āĻļā§āϝ-C

NSError *signOutError;
BOOL status = [[FIRAuth auth] signOut:&signOutError];
if (!status) {
  NSLog(@"Error signing out: %@", signOutError);
  return;
}

āφāĻĒāύāĻŋ āĻĒā§āϰāĻŽāĻžāĻŖā§€āĻ•āϰāĻŖ āĻ¤ā§āϰ⧁āϟāĻŋāϰ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻĒāϰāĻŋāϏāϰ⧇āϰ āϜāĻ¨ā§āϝ āĻ¤ā§āϰ⧁āϟāĻŋ āĻšā§āϝāĻžāĻ¨ā§āĻĄāϞāĻŋāĻ‚ āϕ⧋āĻĄ āϝ⧋āĻ— āĻ•āϰāϤ⧇ āϚāĻžāχāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤ āĻšā§āϝāĻžāĻ¨ā§āĻĄā§‡āϞ āĻ¤ā§āϰ⧁āϟāĻŋ āĻĻ⧇āϖ⧁āύ.