First of all, it’s necessary to make sure that you have an existing app created at Back4App. However, if you are a new user, you can check this tutorial to learn how to create one.
2 - Add the Sign In with Apple capability to your XCode project
In your XCode Project, click on the Target (1) and go to the Signing & Capabilities tab (2).
Click the + Capability button (3) and add the Sign In with Apple capability (4).
While there, choose your Bundle Identifier (5) and hold that information because we will need it later.
3 - Create a new Service ID
Log into your Apple Developer account and go to the Identifiers section. Check if your created Bundle Identifier is there
Click the Bundle Identifier and scroll down. Check if the Sign In with Apple is selected
Click Edit and make sure the Enable as a primary App ID is selected
If everything is right, save and exit.
4 - Set up Parse Auth for Apple
Go to the Back4App website, log in, and then find your app. After that, click on Server Settings search for the Apple Login block, and select Settings.
The Apple Login section looks like this:
Now, you just need to paste your Bundle ID in the field below and click on the button to save.
In case you face any trouble while integrating Apple Login, please contact our team via chat!
5 - Option 1 - Download our Template
There is some coding involved in making Sign in With Apple work, so we created this template that you can download, and change the Bundle Identifier, the App Id, and Client Key.
The code is fully documented so it is a good starting point.
If you prefer to read through this doc, please go on to the next step.
6 - Option 2 - Manually write code
Inside your view, add the AuthenticationServices framework and create the AuthDelegate that will handle the PFUserAuthenticationDelegate:
7 - Implement your Delegates for the ViewController
Implement the ASAuthorizationControllerDelegate and ASAuthorizationControllerPresentationContextProviding for the ViewController:
Swift
1 class ViewController: UIViewController, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding
8 - Add the Sign In with Apple button
The ViewDidAppear is a good place for it. If you choose other places, remember to call it just once:
Swift
1 override func viewDidAppear(_ animated: Bool){2 super.viewDidAppear(animated)34// Sign In with Apple button5 let signInWithAppleButton =ASAuthorizationAppleIDButton()67// set this so the button will use auto layout constraint8 signInWithAppleButton.translatesAutoresizingMaskIntoConstraints =false910// add the button to the view controller root view11 self.view.addSubview(signInWithAppleButton)1213// set constraint14 NSLayoutConstraint.activate([15 signInWithAppleButton.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant:50.0),16 signInWithAppleButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant:-50.0),17 signInWithAppleButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant:-70.0),18 signInWithAppleButton.heightAnchor.constraint(equalToConstant:50.0)19])2021// the function that will be executed when user tap the button22 signInWithAppleButton.addTarget(self, action: #selector(appleSignInTapped),for:.touchUpInside)23}
The appleSignInTapped in the last line must also be defined inside the ViewController class:
Swift
1// This is the function that will be executed when user taps the button2 @objc func appleSignInTapped(){3 let provider =ASAuthorizationAppleIDProvider()4 let request = provider.createRequest()5// request full name and email from the user's Apple ID6 request.requestedScopes =[.fullName,.email]78// pass the request to the initializer of the controller9 let authController =ASAuthorizationController(authorizationRequests:[request])1011// similar to delegate, this will ask the view controller12// which window to present the ASAuthorizationController13 authController.presentationContextProvider = self
1415// delegate functions will be called when user data is16// successfully retrieved or error occured17 authController.delegate = self
1819// show the Sign-in with Apple dialog20 authController.performRequests()21}
9 - The presentationContextProvider
The presentationContextProvider (ASAuthorizationControllerPresentationContextProviding) will ask for which window should display the Authorization dialog. As we are going to display it in the same window, we must return self.view.window:
Swift
1 func presentationAnchor(for controller: ASAuthorizationController)-> ASPresentationAnchor {2// return the current view window3return self.view.window!4}
10 - Handling the delegate ASAuthorizationControllerDelegate
There are a few options that we must handle when the delegate is called, so let’s add some code to handle those options distinctly:
Swift
1 func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error){2print("authorization error")3 guard let error = error as? ASAuthorizationError else{4return5}67 switch error.code {8 case .canceled:9// user press "cancel" during the login prompt10print("Canceled")11 case .unknown:12// user didn't login their Apple ID on the device13print("Unknown")14 case .invalidResponse:15// invalid response received from the login16print("Invalid Respone")17 case .notHandled:18// authorization request not handled, maybe internet failure during login19print("Not handled")20 case .failed:21// authorization failed22print("Failed")23 @unknown default:24print("Default")25}26}
11 - Handling the delegate for didCompleteWithAuthorization
When we successfully authenticate, we can retrieve the authorized information:
Swift
1 func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization){23if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {4// unique ID for each user, this uniqueID will always be returned5 let userID = appleIDCredential.user
6print("UserID: "+ userID)78// if needed, save it to user defaults by uncommenting the line below9//UserDefaults.standard.set(appleIDCredential.user, forKey: "userID")1011// optional, might be nil12 let email = appleIDCredential.email
13print("Email: "+(email ??"no email"))1415// optional, might be nil16 let givenName = appleIDCredential.fullName?.givenName
17print("Given Name: "+(givenName ??"no given name"))1819// optional, might be nil20 let familyName = appleIDCredential.fullName?.familyName
21print("Family Name: "+(familyName ??"no family name"))2223// optional, might be nil24 let nickName = appleIDCredential.fullName?.nickname
25print("Nick Name: "+(nickName ??"no nick name"))26/*
27 useful for server side, the app can send identityToken and authorizationCode
28 to the server for verification purpose
29 */30 var identityToken : String?31if let token = appleIDCredential.identityToken {32 identityToken =String(bytes: token, encoding:.utf8)33print("Identity Token: "+(identityToken ??"no identity token"))34}3536 var authorizationCode : String?37if let code = appleIDCredential.authorizationCode {38 authorizationCode =String(bytes: code, encoding:.utf8)39print("Authorization Code: "+(authorizationCode ??"no auth code"))40}4142// do what you want with the data here4344}45}
That’s the place where we can also add code for logging in Parse. So right after the do what you want with the data here comment, let’s add:
Swift
1 PFUser.logInWithAuthType(inBackground:"apple", authData:["token":String(identityToken!),"id": userID]).continueWith { task -> Any?in2if((task.error)!= nil){3//DispatchQueue.main.async {4print("Could not login.\nPlease try again.")5print("Error with parse login after SIWA: \(task.error!.localizedDescription)")6//}7return task
8}9print("Successfuly signed in with Apple")10return nil
11}