# Authentication for Your iOS Apps with Apple Sign-in and Atlas App Services

Mobile device authentication serves as the crucial first line of defense against potential intruders who aim to exploit personal information, financial data, or private details. As our mobile phones store a wealth of sensitive information, it is imperative to prioritize security while developing apps that ensure user safety. 

Apple sign-in is a powerful solution that places user privacy at the forefront by implementing private email relay functionality. This enables users to shield their email addresses, granting them greater control over their data. Combining this with Atlas App Services provides developers with a streamlined and secure authentication experience. It also simplifies app development, service integration, and data connectivity, eliminating operational overhead. 

In the following tutorial, I will show you how with only a few steps and a little code, you can bring this seamless implementation to your iOS apps! If you also want to follow along and check the code that I’ll be explaining in this article, you can find it in the Github repository. 

## Context

This sample application consists of an iOS app with a “Sign in with Apple” button, where when the user taps on it, it will prompt the authentication native sheet that will allow the user to choose to sign in to your app hiding or showing their email address. Once the sign-up process is completed, the sign-in process gets handled by the Authentication API by Apple. 

## Prerequisites

Since this tutorial’s main focus is on the code implementation with Apple sign-in, a few previous steps are required for it. 

- Have the latest stable version of Xcode installed on your macOS computer, and make sure that the OS is compatible with the version. 
- Have a setup of a valid Apple Developer Account and configure your App ID. You can follow the official Apple documentation.
- Have the Apple Sign-In Capability added to your project. Check out the official Apple sign-in official resources.
- Have the Realm Swift SDK installed on your project and an Atlas App Services app linked to your cluster. Please follow the steps in our Realm Swift SDK documentation on how to create an Alas App Services app.

## Configuring Apple provider on Atlas App Services

In order to follow this tutorial, you will need to have an **Atlas App Services app** created. If not, please follow the steps in our MongoDB documentation. It’s quite easy to set it up! 

First, in your Atlas App Services app, go to **Data Access** -> **Authentication** on the sidebar. 

In the **Authentication Providers** section, enable the **Apple** provider when tapping on the **Edit** button. You’ll see a screen like the one in the screenshot below: 

You will have now to fill the corresponding fields with the following information: 

- **Client ID:** Enter your application’s Bundle ID for the App Services Client ID.
- **Client Secret:** Choose or create a new secret, which is stored in Atlas App Services' back end.
- **Redirect URIs:** You will have to use a URI in order to redirect the authentication. You can use your own custom domain, but if you have a paid tier cluster in Atlas, you can benefit from our Hosting Service!

Click on the “Save Draft” button and your changes will be deployed. 

### Implementing the Apple sign-in authentication functionality

Now, before continuing with this section, please make sure that you have followed our quick start guide to make sure that you have our Realm Swift SDK installed. Moving on to the fun part, it’s time to code!

This is a pretty simple UIKit project, where *LoginViewController.swift* will implement the authentication functionality of Apple sign-in, and if the authenticated user is valid, then a segue will transition to *WelcomeViewController.swift*.

On top of the view controller code, make sure that you import both the AuthenticationServices and RealmSwift frameworks so you have access to their methods. In your Storyboard, add a UIButton of type *ASAuthorizationAppleIDButton* to the *LoginViewController* and link it to its corresponding Swift file.

In the *viewDidLoad()* function of *LoginViewController*, we are going to call *setupAppleSignInButton()*, which is a private function that lays out the Apple sign-in button, provided by the AuthenticationServices API. Here is the code of the functionality.

```swift
// Mark: - IBOutlets
@IBOutlet weak var appleSignInButton: ASAuthorizationAppleIDButton!

// MARK: - View Lifecycle
override func viewDidLoad() {
    super.viewDidLoad()
    setupAppleSignInButton()
}

// MARK: - Private helper
private func setupAppleSignInButton() {
    appleSignInButton.addTarget(self, action: #selector(handleAppleIdRequest), for: .touchUpInside)
    appleSignInButton.cornerRadius = 10
}
```

The private function adds a target to the *appleSignInButton* and gives it a radius of 10 to its corners. The screenshot below shows how the button is laid out in the testing device.

Now, moving to *handleAppleIdRequest*, here is the implementation for it: 

```swift
@objc func handleAppleIdRequest() {
    let appleIDProvider = ASAuthorizationAppleIDProvider()
    let request = appleIDProvider.createRequest()
    request.requestedScopes = .fullName, .email]
    let authorizationController = ASAuthorizationController(authorizationRequests: [request])
    authorizationController.delegate = self
    authorizationController.performRequests()
}
```

This function is a method that handles the initialization of Apple ID authorization using *ASAuthorizationAppleIDProvider* and *ASAuthorizationController* classes. Here is a breakdown of what the function does: 

1. It creates an instance of *ASAuthorizationAppleIDProvider*, which is responsible for generating requests to authenticate users based on their Apple ID.
2. Using the *appleIDProvider* instance, it creates an authorization request when calling *createRequest()*.
3. The request is used to configure the specific data that the app needs to access from the user’s Apple ID. In this case, we are requesting fullName and email.
4. We create an instance of *ASAuthorizationController* that will manage the authorization requests and will also handle any user interactions related to the Apple ID authentication.
5. The *authorizationController* has to set its delegate to self, as the current object will have to conform to the *ASAuthorizationControllerDelegate* protocol.
6. Finally, the specified authorization flows are performed by calling *performRequests()*. This method triggers the system to present the Apple ID login interface to the user. 

As we just mentioned, the view controller has to conform to the *ASAuthorizationControllerDelegate*. To do that, I created an extension of *LoginViewController*, where the implementation of the *didCompleteWithAuthorization* delegate method is where we will handle the successful authentication with the Swift Realm SDK.

```  swift
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
    if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
        let userIdentifier = appleIDCredential.user
        let fullName = appleIDCredential.fullName
        let email = appleIDCredential.email

        guard let identityToken = appleIDCredential.identityToken else {
            return
        }
        let decodedToken = String(decoding: identityToken, as: UTF8.self)
        print(decodedToken)

        realmSignIn(appleToken: decodedToken)
    }
}
```

To resume it in a few lines, this code retrieves the necessary user information from the Apple ID credential if the credentials of the user are successful. We also obtain the *identityToken*, which is the vital piece of information that is needed to use it on the Atlas App Services authentication. 

However, note that this token **has to be decoded** in order to be used on Atlas App Services, and for that, you can use the *String(decoding:, as:)* method. 

Once the token is decoded, it is a JWT that contains claims about the user signed by Apple Authentication Service. Then the *realmSignIn()* private method is called and the decoded token is passed as a parameter so the authentication can be handled. 

```swift
private func realmSignIn(appleToken: String) {
    let credentials = Credentials.apple(idToken: appleToken)
    app.login(credentials: credentials) { (result) in
        switch result {
        case .failure(let error):
            print("Realm Login failed: \(error.localizedDescription)")

        case .success(_):
            DispatchQueue.main.async {
                print("Successful Login")
                self.performSegue(withIdentifier: "goToWelcomeViewController", sender: nil)
            }
        }
    }
}
```

The *realmSignIn()* private function handles the login into Atlas App Services. This function will allow you to authenticate your users that will be connected to your app without any additional hassle. First, the credentials are generated by *Credentials.apple(idToken:)*, where the decoded Apple token is passed as a parameter. 

If the login is successful, then the code performs a segue and goes to the main screen of the project, *WelcomeViewController*. If it fails, then it will print an error message. Of course, feel free to adapt this error to whatever suits you better for your use case (i.e., an alert message). 

Another interesting delegate method in terms of error handling is the *didCompleteWithError()* delegate function, which will get triggered if there is an error during the Apple ID authentication. You can use this one to provide some feedback to the user and improve the UX of your application.

## Important note

One of the biggest perks of Apple sign-in authentication, as it was mentioned earlier, is the flexibility it gives to the user regarding what gets shared with your app. This means that if the user decides to hide their email address and not to share their full name as the code was requested earlier through the *requestedScopes* definition, you will receive **an empty string** in the response. In the case of the email address, it will be a *nil* value. 

If your iOS application has a use case where you want to establish communication with your users, you will need to implement [communication using Apple's private email relay service. You should avoid asking the user for their email in other parts of the app too, as it could potentially create a rejection on the App Store review.

## Repository

The code for this project can be found in the Github repository. 

I hope you found this tutorial helpful. I encourage you to explore our Realm Swift SDK documentation to discover all the benefits that it can offer to you when building iOS apps. We have plenty of resources available to help you learn and implement these features. So go ahead, dive in, and see what Atlas App Services has in store for your app development journey. 

If you have any questions or comments don’t hesitate to head over to our Community Forums to continue the conversation. Happy coding!