Authenticate Using Apple with JavaScript

You can let your users authenticate with Firebase using their Apple ID by using the Firebase SDK to carry out the end-to-end OAuth 2.0 sign-in flow.

Before you begin

To sign in users using Apple, first configure Sign In with Apple on Apple's developer site, then enable Apple as a sign-in provider for your Firebase project.

Join the Apple Developer Program

Sign In with Apple can only be configured by members of the Apple Developer Program.

Configure Sign In with Apple

On the Apple Developer site, do the following:

  1. Associate your website to your app as described in the first section of Configure Sign In with Apple for the web. When prompted, register the following URL as a Return URL:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler

    You can get your Firebase project ID on the Firebase Console settings page.

    When you're done, take note of your new Service ID, which you'll need in the next section.

  2. Verify ownership of the redirect domain as described in the second section of Configure Sign In with Apple for the web. This process requires you to download a file and temporarily host it at the following URL:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/.well-known/apple-developer-domain-association.txt

    For example, if you aren't already using Firebase Hosting:

    mkdir hosting && cd hosting
    npm i -g firebase-tools
    firebase use --add
    firebase init hosting
    mkdir -p public/.well-known
    # Download apple-developer-domain-association.txt to public/.well-known/
    firebase deploy --only hosting
    

    See the Firebase Hosting docs for details on hosting files on your Firebase domain.

  3. Create a Sign In with Apple private key. You'll need your new private key and key ID in the next section.
  4. If you use any of Firebase Authentication's features that send emails to users, including email link sign-in, email address verification, account change revocation, and others, configure the Apple private email relay service and register noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com (or your customized email template domain) so Apple can relay emails sent by Firebase Authentication to anonymized Apple email addresses.

Enable Apple as a sign-in provider

  1. Add Firebase to your project.
  2. In the Firebase console, open the Auth section. On the Sign in method tab, enable the Apple provider. Specify the Service ID you created in the previous section. Also, in the OAuth code flow configuration section, specify your Apple Team ID and the private key and key ID you created in the previous section.

Comply with Apple anonymized data requirements

Sign In with Apple gives users the option of anonymizing their data, including their email address, when signing in. Users who choose this option have email addresses with the domain privaterelay.appleid.com. When you use Sign In with Apple in your app, you must comply with any applicable developer policies or terms from Apple regarding these anonymized Apple IDs.

This includes obtaining any required user consent before you associate any directly identifying personal information with an anonymized Apple ID. When using Firebase Authentication, this may include the following actions:

  • Link an email address to an anonymized Apple ID or vice versa.
  • Link a phone number to an anonymized Apple ID or vice versa
  • Link a non-anonymous social credential (Facebook, Google, etc) to an anonymized Apple ID or vice versa.

The above list is not exhaustive. Refer to the Apple Developer Program License Agreement in the Membership section of your developer account to make sure your app meets Apple's requirements.

Handle the sign-in flow with the Firebase SDK

If you are building a web app, the easiest way to authenticate your users with Firebase using their Apple accounts is to handle the entire sign-in flow with the Firebase JavaScript SDK.

To handle the sign-in flow with the Firebase JavaScript SDK, follow these steps:

  1. Create an instance of an OAuthProvider using the corresponding provider ID apple.com.

    var provider = new firebase.auth.OAuthProvider('apple.com');
    
  2. Optional: Specify additional OAuth 2.0 scopes beyond the default that you want to request from the authentication provider.

    provider.addScope('email');
    provider.addScope('name');
    

    By default, when One account per email address is enabled, Firebase requests email and name scopes. If you change this setting to Multiple accounts per email address, Firebase doesn't request any scopes from Apple unless you specify them.

  3. Optional: If you want to display Apple's sign-in screen in a language other than English, set the locale parameter. See the Sign In with Apple docs for the supported locales.

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });
    
  4. Authenticate with Firebase using the OAuth provider object. You can prompt your users to sign in with their Apple Accounts either by opening a pop-up window or by redirecting to the sign-in page. The redirect method is preferred on mobile devices.

    • To sign in with a pop-up window, call signInWithPopup():

      firebase
        .auth()
        .signInWithPopup(provider)
        .then(function(result) {
          // The signed-in user info.
          var user = result.user;
           // You can also get the Apple OAuth Access and ID Tokens.
          var accessToken = result.credential.accessToken;
          var idToken = result.credential.idToken;
      
          // ...
        })
        .catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          // The email of the user's account used.
          var email = error.email;
          // The firebase.auth.AuthCredential type that was used.
          var credential = error.credential;
      
          // ...
        });
      
    • To sign in by redirecting to the sign-in page, call signInWithRedirect():

      firebase.auth().signInWithRedirect(provider);
      

      After the user completes sign-in and returns to the page, you can get the sign-in result by calling getRedirectResult():

      // Result from Redirect auth flow.
      firebase
        .auth()
        .getRedirectResult()
        .then(function(result) {
          if (result.credential) {
            // You can get the Apple OAuth Access and ID Tokens.
            var accessToken = result.credential.accessToken;
            var idToken = result.credential.idToken;
      
            // ...
          }
          // The signed-in user info.
          var user = result.user;
        })
        .catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          // The email of the user's account used.
          var email = error.email;
          // The firebase.auth.AuthCredential type that was used.
          var credential = error.credential;
      
          // ...
        });
      

      This is also where you can catch and handle errors. For a list of error codes, see the API reference.

    Unlike other providers supported by Firebase Auth, Apple does not provide a photo URL.

    Also, when the user chooses not to share their email with the app, Apple provisions a unique email address for that user (of the form xyz@privaterelay.appleid.com), which it shares with your app. If you configured the private email relay service, Apple forwards emails sent to the anonymized address to the user's real email address.

    Apple only shares user information such as the display name with apps the first time a user signs in. Usually, Firebase stores the display name the first time a user signs in with Apple, which you can get with firebase.auth().currentUser.displayName. However, if you previously used Apple to sign a user in to the app without using Firebase, Apple will not provide Firebase with the user's display name.

Reauthentication and account linking

The same pattern can be used with reauthenticateWithPopup() and reauthenticateWithRedirect(), which you can use to retrieve a fresh credential for sensitive operations that require recent sign-in:

const provider = new firebase.auth.OAuthProvider('apple.com');
firebase
  .auth()
  .currentUser
  .reauthenticateWithPopup(provider)
  .then(function(result) {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.

    // The signed-in user info.
    var user = result.user;
     // You can also get the Apple OAuth Access and ID Tokens.
    var accessToken = result.credential.accessToken;
    var idToken = result.credential.idToken;

    // ...
  })
  .catch(function(error) {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // The email of the user's account used.
    var email = error.email;
    // The firebase.auth.AuthCredential type that was used.
    var credential = error.credential;

    // ...
  });

And, you can use linkWithPopup() and linkWithRedirect(), to link different identity providers to existing accounts.

Note that Apple requires you to get explicit consent from users before you link their Apple accounts to other data.

For example, to link a Facebook account to the current Firebase account, use the access token you got from signing the user in to Facebook:

const provider = new firebase.auth.FacebookAuthProvider();
provider.addScope('user_birthday');
// Assuming the current user is an Apple user linking a Facebook provider.
firebase.auth().currentUser.linkWithPopup(provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // Facebook additional data available in result.additionalUserInfo.profile,
      // Additional Facebook OAuth access token can also be retrieved.
      // result.credential.accessToken

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

Authenticate with Firebase in a Chrome extension

If you are building a Chrome extension app, you must whitelist your Chrome extension ID:

  1. Open your project in the Firebase console.
  2. In the Authentication section, open the Sign-in method page.
  3. Add a URI like the following to the list of Authorized Domains:
    chrome-extension://CHROME_EXTENSION_ID

Only popup operations (signInWithPopup and linkWithPopup) are available to Chrome extensions, as Chrome extensions cannot use HTTP redirects. You should call these methods from a background script rather than a browser action popup, as the authentication popup will cancel the browser action popup.

In your Chrome extension's manifest file make sure that you add the https://apis.google.com URL to the content_security_policy whitelist.

Note that you must still verify the custom domain with Apple similarly to the default firebaseapp.com domain:

http://auth.custom.example.com/.well-known/apple-developer-domain-association.txt

Advanced: Authenticate with Firebase in Node.js

To authenticate with Firebase in a Node.js application:

  1. Sign in the user with their Apple Account and get the user's Apple ID token. You can accomplish this in several ways. For example, if your Node.js app has a browser front end:

    1. On your backend, generate a random string (a "nonce") and compute its SHA256 hash. The nonce is a one-time use value you use to validate a single round trip between your backend and Apple's auth servers.

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = function(length) {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        var nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.substr(0, length);
      };
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256').update(nonce).digest().toString('hex');
      
    2. On your sign-in page, specify the hashed nonce in your Sign In with Apple configuration:

      <script src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
      <div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
      <script>
          AppleID.auth.init({
              clientId: YOUR_APPLE_CLIENT_ID,
              scope: 'name email',
              redirectURI: URL_TO_YOUR_REDIRECT_HANDLER,  // See the next step.
              state: '[STATE]',  // Optional value that Apple will send back to you
                                 // so you can return users to the same context after
                                 // they sign in.
              nonce: HASHED_NONCE  // The hashed nonce you generated in the previous step.
          });
      </script>
      
    3. Get the Apple ID token from POSTed auth response server-side:

      app.post('/redirect', (req, res) => {
        const savedState = req.cookies.__session;
        const code = req.body.code;
        const state = req.body.state;
        const appleIdToken = req.body.id_token;
        if (savedState !== state || !code) {
          res.status(403).send('403: Permission denied');
        } else {
          // Sign in with Firebase using appleIdToken. (See next step).
        }
      });
      

    Also see Configuring Your Webpage for Sign In with Apple.

  2. After you get the user's Apple ID token, use it to build a Credential object and then sign in the user with the credential:

    // Build Firebase credential with the Apple ID token.
    const provider = new firebase.auth.OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    firebase.auth().signInWithCredential(credential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });
    

Next steps

After a user signs in for the first time, a new user account is created and linked to the credentials—that is, the user name and password, phone number, or auth provider information—the user signed in with. This new account is stored as part of your Firebase project, and can be used to identify a user across every app in your project, regardless of how the user signs in.

  • In your apps, the recommended way to know the auth status of your user is to set an observer on the Auth object. You can then get the user's basic profile information from the User object. See Manage Users.

  • In your Firebase Realtime Database and Cloud Storage Security Rules, you can get the signed-in user's unique user ID from the auth variable, and use it to control what data a user can access.

You can allow users to sign in to your app using multiple authentication providers by linking auth provider credentials to an existing user account.

To sign out a user, call signOut:

firebase.auth().signOut().then(function() {
  // Sign-out successful.
}).catch(function(error) {
  // An error happened.
});