Server-Side Sign in with Apple

Nov 15 2022 · Swift 5.6, macOS 12, iOS 15, Xcode 13.3

Part 1: Add Sign in with Apple to an iOS Project

03. Add Sign in with Apple to Your iOS App

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 02. Add Sign in with Apple to Your Vapor App Next episode: 04. Connect Your iOS App to Your Vapor App

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 03. Add Sign in with Apple to Your iOS App

In this video we’re going to add Sign in with Apple to your iOS app and learn how to show the button on the login screen. Please note that you’ll need an Apple developer account to test this out.

Adding the capability

Open the TILiOS project in Xcode and navigate to the TILiOS target. Change the bundle identifier to something unique to your project. For example, this video will use dev.timc.siwa-demo.TILiOS. Next click on the Signing & Capabilities tab and select your development team to ensure the app is signed correctly.

Finally, click on the add new capability button, search for Sign in with Apple and select it. This allows you to use Sign in with Apple in your app.

Displaying the button

Now that you can do so, it’s time to show the Sign in with Apple button on the log in screen. Open LoginView.swift and at the top of the file, import AuthenticationServices:

import AuthenticationServices

AuthenticationServices provides a built in view for the Sign in with Apple button. Insert it below the AsyncButton for Log In, using the signIn label:

SignInWithAppleButton(.signIn) { request in
  
} onCompletion: { result in

}

Then, in the request closure, you need to specify the scopes. You want to request full name and email to be able to register the user with the Vapor app:

request.requestedScopes = [.fullName, .email]

Next, create a new function called handleSIWA that takes a result and returns a Token. Annotate the function with @MainActor:

@MainActor
func handleSIWA(result: Result<ASAuthorization, Error>) async throws -> Token {

}

Inside, switch on the result and if there’s an error, display the error dialogue, print the error and throw it:

switch result {
case .failure(let error):
  self.showingLoginErrorAlert = true
  print("Error \(error)")
  throw error
}

The success case gets an ASAuthorization from the result. Add that case and ensure you can get the credential, otherwise, throw an error:

case .success(let authResult):
  if let credential = authResult.credential as? ASAuthorizationAppleIDCredential {

  } else {
    self.showingLoginErrorAlert = true
    throw AuthError.badResponse
  }

If there are credentials, extract the JWT for the identity as a String and the name:

guard
    let identityToken = credential.identityToken,
    let tokenString = String(data: identityToken, encoding: .utf8)
else {
    print("Failed to get token from credential")
    self.showingLoginErrorAlert = true
    throw AuthError.badResponse
}
let name: String?
if let nameProvided = credential.fullName {
    name = "\(nameProvided.givenName ?? "") \(nameProvided.familyName ?? "")"
} else {
    name = nil
}

Then, throw an error to allow the function to compile:

throw AuthError.notLoggedIn

Finally, hook up the Sign in with Apple button with the handleSIWA function. In the completion handler, create a new Task to allow the async function to execute and get the token, even though that’s not implemented yet:

Task {
    let apiToken = try await handleSIWA(result: result)
}

Once you have the token, assign it to the Auth EnvironmentObject:

auth.token = apiToken.value

This triggers a refresh of the app and marks the user as signed in. Now users can trigger the Sign in with Apple flow when logging in to the app. Build the app to make sure everything compiles.