DEV Community

Cover image for How to add "signin with apple" to your website
Arpit
Arpit

Posted on • Edited on • Originally published at arpit.one

How to add "signin with apple" to your website

Why Use Apple

Many websites have provide users a way to sign in to their applications via third party services like Google, Twitter, GitHub etc. We're trying to provide users with a more convenient solution where they can use their already existing accounts. Apple also provides a way for you to do this but their process can be very challenging if you're attempting this for the first time. In this blog post I'd like to show you how to integrate "sign in with apple" into your web application. This is about react and nodejs but with some understanding you can make it work with your own tech stack.

What We're Aiming For

  1. User visits your website.
  2. User presses the "Sign In with Apple" button.
  3. A pop up window opens that takes the user to an apple website where they login into their apple account.
  4. After successful login apple sends some information about the user back to the window where we initiated the signin process.
  5. We capture the data and send it to our server for verification and storing the information in our database.

Initial Setup

In short, you need to have some setup and configs in hand before you start working on the code. In summary, you'll need to do these things -

  1. Create an App ID.
  2. Create a Serve ID.
  3. Register the domains for your website.

The following are some screenshots to explain the process of App ID and Service ID creation. If you're already familiar with this process click here to jump to the next section.

App ID

  1. Open Your developer console and find Certificates IDs & Profiles
    Certificates IDs & Profiles

  2. Click on Identifiers in the side panel. Then click the plus symbol next to Identifiers to create a new App ID.
    Final App ID list

  3. Select App IDs
    Create App Id

  4. Select Type App
    App vs app Clip

  5. Use a descriptive name for your application, I've used Example Application here. We'll choose an explicit style Bundle ID for now, use apple's suggested reverse domain style for proper namespacing, the string can be anything but you should stick to convention. I've used com.example here.
    Register App Id

Service ID

  1. Go back to the developer console and create a new identifier. This time select Services IDs.
    New ID Service ID

  2. Register a service with a proper description, I've used Example Application Signin here. For the identifier we'll follow the convention and use com.example.signin.
    Register a Service ID

  3. Your new Service ID is created, find it by using the dropdown you see on the left.
    Switch to service ID

  4. Click on your Service ID that you just created.
    Service ID List

  5. After you hit continue and save click in the identifier again. You'll be greeted with a checkbox tha say Sign In with Apple. Click on Configure.
    Enter a description for Service ID

  6. A modal will popup, register your domain here.

    • As your Primary App ID, choose the one we just created in the previous section.
    • In the domains section add the domain where this service will be used.
    • The return URL is the location to which apple will redirect us after authentication is completed. This is also the location where apple will send the user data after authentication. If it's a link to your server API, then apple will send a POST request to this URL. However, we will use location of our frontend as the return URL, and the data will be captured on the client side(more about this in the next section). I've assigned http://example.com for this example. Domain Registration

The Frontend

The most straight forward approach to using apple signin on your front end is to use the library provided by apple. Add the following CDN link to your page to load the library apple has provided.

<script
  type="text/javascript"
  src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"
></script>
Enter fullscreen mode Exit fullscreen mode

This will make a global AppleID object available to you for use. Here's how we'll use them.

/**
 * This function will initialize the `AppleID.auth` object with parameter we pass in.
 */
const initApple = () => {
  window.AppleID.auth.init({
    clientId: "com.example.signin", // This is the service ID we created.
    scope: "name email", // To tell apple we want the user name and emails fields in the response it sends us.
    redirectURI: "http://example.com", // As registered along with our service ID
    state: "origin:web", // Any string of your choice that you may use for some logic. It's optional and you may omit it.
    usePopup: true, // Important if we want to capture the data apple sends on the client side.
  });
};
Enter fullscreen mode Exit fullscreen mode

NOTE

Apple makes a POST request to the redirectURI that you specify, normally you'd have a link to your backend API where the data gets posted, however we can bypass this and capture the information on the frontend by using the usePopup flag. This will instead capture apple's response on the client side.


The below function is how we start the apple authentication workflow. It will open a popup window where a user will be asked to input their apple email and password.
After a successful login apple will send a response object with user data that we can store in our backend.

/**
 * This function is where the magic happens.
 * This is a simple example, ideally you'll have catch block as well to handle authentication failure.
 */
const singInApple = async () => {
  const response = await window.AppleID.auth.signIn();

  return response;
};
Enter fullscreen mode Exit fullscreen mode

This is what the response will look like (for first time users).

{
  "authorization": {
    "state": "[STATE]", // The state string we used in the initApple function
    "code": "[CODE]", // A single-use authentication code that is valid for five minutes. We won't be using this for now.
    "id_token": "[ID_TOKEN]" // This is what we're really interested in. This is JSON web token we'll be decoding in the backend.
  },
  "user": {
    // User details object, we'll be storing this data in the backend as well.
    "email": "[EMAIL]",
    "name": {
      "firstName": "[FIRST_NAME]",
      "lastName": "[LAST_NAME]"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

NOTE

The user object is only sent the first time a user logs in, the rest of the times apple will only send the authorization object.


Great! now that we have authenticated the user from apple's perspective we need to verify the user in the backend before authenticating them. You can use whatever utility you wish axios, fetch; it doesn't matter as long as you get your data to your server.

The Backend

This is specific to Node.js but remember id_token is a JSON web token and you can use libraries in other languages to decode it.
For now we'll use a library tailor made for apple sign in called apple-signin-auth.

Install simply with -

npm i apple-signin-auth
Enter fullscreen mode Exit fullscreen mode

or

yarn add apple-signin-auth
Enter fullscreen mode Exit fullscreen mode

Now inside your controller, receive the token and decode it.

const appleSignin = require("apple-signin-auth");


const { authorization, user } = req.body;

try {
  const { sub: userAppleId } = await appleSignin.verifyIdToken(
    authorization.id_token, // We need to pass the token that we wish to decode.
    {
      audience: "com.example.signin", // client id - The same one we used  on the frontend, this is the secret key used for encoding and decoding the token.
      ignoreExpiration: true, // Token will not expire unless you manually do so.
    }
  );
} catch (err) {
  // Token is not verified
  console.error(err);
}
Enter fullscreen mode Exit fullscreen mode

The decoded message here userAppleId it is unique identifier for a single user and and persists on multiple logins.

You can use your login workflow now.

  1. Query your database to find if userAppleId exists.
  2. If it exists then great! You have your user.
  3. If it doesn't then you need to create a new user linked to this apple id, (The user details, email and name are only sent the first time a user logs into so you need to save those as well.)

Further Reading

Top comments (12)

Collapse
 
victortommasi profile image
tommasi.dev

Thank you so much! Saved my day! I wasn't sure how to do the sign in process with popup option setted true.

PS: Fix the note:
"The user object is only sent the first time a user logs in, the rest of the times apple will only send the authentication object.". Instead of "authentication" object write "authorization" object.

Collapse
 
heyitsarpit profile image
Arpit

Thanks for spotting the mistake, updated!

Collapse
 
aidv profile image
aidv

On mobile safari, it behaves quite weird.

After sign in is successful, the error "popup_closed_by_user" is fired, and the page redirects to the redirect_uri, which is practically a blank white page.

Any ideas on why this is happening?

Collapse
 
romalyt profile image
Roman

Oh my god, thank you! Saved my day as well!

Collapse
 
jezmck profile image
Jez McKean

The key takeaway for me was

Apple makes a POST request to the redirectURI that you specify, normally you'd have a link to your backend API where the data gets posted, however we can bypass this and capture the information on the frontend by using the usePopup flag. This will instead capture apple's response on the client side.

Collapse
 
abc_abc_ee7ab7696b1fafcf9 profile image
abc abc • Edited

Hello sir i am following your blog for adding sign in with apple but after putting email and password and after that clicked on continue then after page disappears and not signed in to website
Also not getting any authorization object or user object
Please help me in that ...

Collapse
 
diana0604 profile image
Diana0604

I've got a question. If you didn't have the popup, you'd still have the option for the redirectURI to be a frontend url, right? I have done this in the past for Twitter and you can just redirect to the same page you're in

Collapse
 
__e10aa8198 profile image
Андрей некрасов • Edited

Do I understand correctly that to create an Sign In with Apple to website I need a developer account? Developer account costs $100.

Collapse
 
marcosfitzsimons profile image
Marcos Fitzsimons

Yes. You need paid developer account

Collapse
 
pubkey profile image
Daniel M

Can you show how to do the login without having to use the js file from the apple cdn?
Like manually opening the popup and handling the events.

Collapse
 
abhijith profile image
Abhijith cv

did you got this

Collapse
 
frankgracy profile image
Grace Frank

I really appreicate this detailed step by step process. Even apple documentation dosent explain this as well as you did.