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
- User visits your website.
- User presses the "Sign In with Apple" button.
- A pop up window opens that takes the user to an apple website where they login into their apple account.
- After successful login apple sends some information about the user back to the window where we initiated the signin process.
- 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 -
- Create an App ID.
- Create a Serve ID.
- 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
Open Your developer console and find
Certificates IDs & Profiles
Click on Identifiers in the side panel. Then click the plus symbol next to
Identifiers
to create a new App ID.
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 usedcom.example
here.
Service ID
Go back to the developer console and create a new identifier. This time select
Services IDs
.
Register a service with a proper description, I've used
Example Application Signin
here. For the identifier we'll follow the convention and usecom.example.signin
.
Your new Service ID is created, find it by using the dropdown you see on the left.
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.
-
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.
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>
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.
});
};
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;
};
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]"
}
}
}
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
or
yarn add apple-signin-auth
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);
}
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.
- Query your database to find if
userAppleId
exists. - If it exists then great! You have your user.
- 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.)
Top comments (12)
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.
Thanks for spotting the mistake, updated!
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?
Oh my god, thank you! Saved my day as well!
The key takeaway for me was
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 ...
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
Do I understand correctly that to create an Sign In with Apple to website I need a developer account? Developer account costs $100.
Yes. You need paid developer account
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.
did you got this
I really appreicate this detailed step by step process. Even apple documentation dosent explain this as well as you did.