Firebase, Apple sign up, SwiftUI - ASAuthorizationControllerDelegate success function not called

362 Views Asked by At

I've implemented my own AppleSignUpButton. It calls this piece of code to do the actual Apple sigThe spinner just keeps spinning.

When I press cancel this function is called as expected:

func authorizationController(controller _: ASAuthorizationController, didCompleteWithError error: Error) {..}

So my only problem is with this one:

func authorizationController(controller _: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {..}

This is my class that handles Apple Sign Up:

import AuthenticationServices
import CryptoKit
import Firebase
import FirebaseAuth
import Foundation

@objc class AppleAuthProvider: NSObject, AuthProvider {
    
    @Published var loggedInUser: FIRUser?
    
    var completion: ((Result<User, Error>) -> Void)?

    private var currentNonce: String?

    func signIn(completion: @escaping (Result<User, Error>) -> Void) {
        self.completion = completion

        startSignInWithAppleFlow()
    }

    func signOut(completion _: @escaping (Result<Void, Error>) -> Void) {
        ()
    }

    func startSignInWithAppleFlow() {
        let nonce = randomNonceString()
        currentNonce = nonce
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.fullName, .email]
        request.nonce = sha256(nonce)

        let authorizationController = ASAuthorizationController(authorizationRequests: [request])
        authorizationController.delegate = self
        authorizationController.performRequests()
    }

    private func randomNonceString(length: Int = 32) -> String {
        precondition(length > 0)
        let charset: [Character] =
            Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
        var result = ""
        var remainingLength = length

        while remainingLength > 0 {
            let randoms: [UInt8] = (0 ..< 16).map { _ in
                var random: UInt8 = 0
                let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
                if errorCode != errSecSuccess {
                    completion?(.failure(fatalError(
                        "Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)"
                    )))
                }
                return random
            }

            randoms.forEach { random in
                if remainingLength == 0 {
                    return
                }

                if random < charset.count {
                    result.append(charset[Int(random)])
                    remainingLength -= 1
                }
            }
        }

        return result
    }

    private func sha256(_ input: String) -> String {
        let inputData = Data(input.utf8)
        let hashedData = SHA256.hash(data: inputData)
        let hashString = hashedData.compactMap {
            String(format: "%02x", $0)
        }.joined()

        return hashString
    }
}

extension AppleAuthProvider: ASAuthorizationControllerDelegate {
    func authorizationController(controller _: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
            guard let nonce = currentNonce else {
                completion?(.failure(fatalError(
                    "Invalid state: A login callback was received, but no login request was sent."
                )))
                return
            }
            guard let appleIDToken = appleIDCredential.identityToken else {
                completion?(.failure(fatalError(
                    "Unable to fetch identity token"
                )))

                return
            }
            guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
                completion?(.failure(fatalError(
                    "Unable to serialize token string from data: \(appleIDToken.debugDescription)"
                )))
                return
            }
            // Initialize a Firebase credential.
            let credential = OAuthProvider.credential(withProviderID: "apple.com",
                                                      idToken: idTokenString,
                                                      rawNonce: nonce)
            // Sign in with Firebase.
            Auth.auth().signIn(with: credential) { [weak self] _, error in
                if let error = error {
                    self?.completion?(.failure(error))
                } 
               // User is signed in to Firebase with Apple.
               // ...
            }
        }
    }

    func authorizationController(controller _: ASAuthorizationController, didCompleteWithError error: Error) {
        completion?(.failure(fatalError(
            "Sign in with Apple errored: \(error)"
        )))
    }
}
1

There are 1 best solutions below

0
Luda On

It didn't work on the Simulator but works properly on a real device.