Adding Sign in with Apple to your iOS App
Tags: mobile, security, ios, swift
Published: 2020-05-04 16:24:13

---
title: Adding Sign in with Apple to your iOS App
published: true
description: Learn about Sign in with Apple and how to implement it in your iOS app and backend.
tags: Mobile, Security, iOS, Swift
canonical_url: https://getstream.io/blog/adding-sign-in-with-apple-to-your-ios-app
---

Since April 2020, all apps that use a third-party or social login service are required to offer Sign in with Apple if they want to be accepted in the App Store.

In a [previous tutorial](https://getstream.io/blog/imessage-clone-using-streamchat-ios-sdk/), we walked through the process of building a simple clone of Apple's iMessage. In this tutorial, we'll go through the steps of adding [Sign in with Apple](https://developer.apple.com/sign-in-with-apple) to that iMessage clone. If you have an existing app built with [Stream's iOS Chat SDK](https://getstream.io/chat/#chat_ios_link) and want to support this sign-in method, the steps will be similar, and the differences pointed out. If you're not building a messaging app, a good chunk of the information here will still apply, so stick around!

If you get lost during this tutorial, you can always check the completed project in this [GitHub repo](https://github.com/GetStream/sign-in-with-apple-swift-example). If you run into any errors, there's a Troubleshooting section at the end of the repo's README that you can check on.

## What is Sign in with Apple? 

Sign in with Apple makes it easy for users to sign in to your apps and websites using their Apple ID. Instead of filling out forms, verifying email addresses, and choosing new passwords, they can use Sign in with Apple to set up an account and start using your app right away. All accounts are protected with two-factor authentication for superior security, and Apple will not track users' activity in your app or website.

> [Apple Developer Portal: Sign in with Apple](https://developer.apple.com/sign-in-with-apple/)



## What you need

- iOS 13+
- Xcode 11+
- Node.js 10+
- A [Stream](https://getstream.io/accounts/signup/) account
- Enrollment in the [Apple Developer Program](https://developer.apple.com/programs/)

## Step 1: Configuring the client project

If your app is still early in development or using the [iMessage clone project](https://github.com/GetStream/stream-imessage-clone), follow the steps in the image below. If your application is already in production, you can jump to the next image.

![1.1: Select a device you have signed in with Apple ID and 2FA. 1.2: Select your team. 1.3: Choose a unique bundle id.](https://dev-to-uploads.s3.amazonaws.com/i/abk0p47lhrfuekg7bx69.png)

Now, you need to add the Sign in with Apple capability in the "Signing & Capabilities" tab of your target.

![Screenshot of target settings highlighting the capability button and the Sign in with Apple capability](https://dev-to-uploads.s3.amazonaws.com/i/s6oandhrb9ws6moyf6c7.png)

## Step 2: Adding the sign-in button

To add the sign-in button, we'll use the [AuthenticationServices](https://developer.apple.com/documentation/authenticationservices) framework, which provides all the functionality needed, including UI elements.

We also need to add the authentication screen, which will appear before the contacts screen. Let's create an `AuthenticationViewController.swift` file and paste in the following code:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=00-start-auth-view-controller.swift %}

Now, let's add this new screen as the first screen in the storyboard. If you're using the iMessage clone project, it should be the root view controller of the navigation controller. To finish it up, set up a Segue from it to the contacts screen with id `kAuthToContactsSegueId`:

![storyboard with the auth screen with a segue to the contacts screen](https://dev-to-uploads.s3.amazonaws.com/i/ph4qk87aksl303nmt2en.png)

Now, run the project, and you should have a button that, when pressed, leads to the contacts screen.

![Animation of the Sign in with Apple button being pressed and the contacts screen showing up](https://dev-to-uploads.s3.amazonaws.com/i/tgkjurg6o4mlyq2x5tz9.gif)

Of course, there is no real authentication happening here yet. We'll look into that in the next steps.

## Step 3: Setting up the backend

Before we build real authentication into the client, we'll need a backend that can generate a Stream token when given the Apple ID credentials. If you already have a backend, you can use one of Stream's [server-side chat libraries](https://getstream.io/chat/docs/tokens_and_authentication/?language=js) to set it up similarly.

To keep things short, we'll build a simple Node.js/Express backend with one endpoint: `/authenticate`. We'll also use the `node-persist` package to persist new user data the first time they authenticate. If you're not interested in building the backend yourself or are having problems, you can get the complete code in the  [repository](https://github.com/GetStream/sign-in-with-apple-swift-example).

In the terminal, run the following commands:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=01-set-up-backend-bash.sh %}

The following code snippets can be copied in sequence into the index.js.

Let's start coding our index.js by importing the objects we need:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=02-backend-index-requires.js %}

Now, configure the Stream Chat client with the credentials that you get in your Stream dashboard:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=03-stream-chat-credentials.js %}

Configure the Apple Auth client:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=04-configure-apple-auth.js %}

For details on filling those parameters, read `apple-auth`'s [SETUP.md](https://github.com/ananay/apple-auth/blob/master/SETUP.md#create-a-key). 

If you're using something other than Node.js for your backend, there are versions of this library for other languages, such as [Go](https://github.com/BillSJC/appleLogin). If you can't find it for your preferred backend stack, you'll have to read through `apple-auth`'s source code and [Sign in with Apple's API specifications](https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens) to implement something similar from scratch.

Initialize express and the node-persist storage:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=05-init-express-and-persist.js %}

Now, let's start building the handler for the `/authenticate` endpoint by extracting the parameters we need from the request: 

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=06-start-authenticate-handler.js %}

Now, we verify the appleAuthCode with Apple's servers using `apple-auth` and extract the user's email address from the response:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=07-verify-apple-auth-code.js %}

If we have an email, and a name was supplied in the authentication request we need to store that information in our persistent storage:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=08-persist-user-data.js %}

Information other than Apple Uid and auth code is only guaranteed to be given by Apple the first time the user tries to sign in. We use this fact to determine when to register the user, and it's why we need to save the information and resupply it in every authentication response.

Now, let's finish the handler by fetching the user data from local storage and relaying it in the response:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=09-response-with-user-data.js %}

Finally, let's configure the express app to listen on port 4000:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=10-express-listen.js %}

Now, we can close index.js and leave the backend running with the following command:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=11-start-backend.sh %}

If this is working, opening `localhost:4000/authenticate` in your browser will display `Cannot GET /authenticate`, which is OK, because we'll use `POST` in the client application.

## Step 4: Request Authorization with Apple ID

Let's go back to Xcode.

First, we need to code the function to interface with the `/authenticate` endpoint we just created. Let's create a file named `Authentication.swift` and start by defining the request and response structures.

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=12-authentication-structs.swift %}

Thanks to `Codable`, we can easily transform those objects into and from JSON, which comes in very useful as we define the actual function to interface with `/authenticate` by sending `AuthRequest` and receiving `AuthResponse`:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=13-authentication-func.swift %}

Reminder: Sign in with Apple will only work on a real device. Make sure to replace `[your local ip]` with your Mac's local network IP address, which is not `localhost` nor `127.0.0.1`. To find it out, run the following command on a terminal in your Mac:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=14-get-local-ip.sh %}

Now, to authenticate the user with Apple, let's go back to `AuthViewController.swift` and edit the button's press handler to add this behavior:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=15-sign-in-press-handler.swift %}

This implementation will make pressing the Sign in with Apple button trigger the Sign in with Apple screen.

![Animation showing the Sign in with Apple button being pressed and the Sign in with Apple modal showing up](https://dev-to-uploads.s3.amazonaws.com/i/y02iod1o0q20ovzvsctr.gif)

However, it won't compile yet, because we haven't conformed `AuthViewController` to a couple of required protocols.

We need conform `AuthViewController` to `ASAuthorizationControllerPresentationContextProviding` to tell Sign in with Apple which window to render the flow in:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=16-authvc-context-providing.swift %}

Most importantly, we also need the conformance to `ASAuthorizationControllerDelegate`, which will let us receive the Apple credentials after the user completes the sign-in flow, which we can then use to authenticate, then configure our Stream client and move to the contacts screen:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=17-auth-controller-delegate.swift %}

Finally, we have a functioning Sign in with Apple implementation:

![Animation showing user authenticating successfully with Sign in with Apple and being moved to the contacts screen](https://dev-to-uploads.s3.amazonaws.com/i/t29m9mi85qjdge1aayln.gif)

Since it's a new user, we don't have any contacts showing.

The backend logs should look similar to this:

{% gist https://gist.github.com/cardoso/de614f1b770a9404215eba93269fa559 file=18-auth-backend-log-sample.sh %}

## Wrapping up

Congratulations! You can now build Sign in with Apple authentication into any iOS app. Make sure to read Sign in with Apple's [guidelines and documentation](https://developer.apple.com/sign-in-with-apple/get-started/) to keep up-to-date with the requirements and announcements. Also, for your apps that need social media or messaging features, check out [Stream](https://getstream.io)'s documentation for [activity feeds](https://getstream.io/docs/) and [chat messaging](https://getstream.io/chat/docs/).

Thanks for reading and happy coding!