ASAuthorizationController delegate inside class not called

I have a class where I want to handle the Sign in with Apple logic. I have created an ASAuthorizationController, set the presentationContextProvider to be my view controller and set the delegate to the class itself. When I perform the requests, the system dialog shows up. But upon canceling, my delegate method does not get called.

Here is my class:


final class AppleSignInProvider: NSObject {
    typealias CompletionHandler = (Result<AuthCredential, Error>) -> Void

    enum AuthError: LocalizedError {
        case credential
        case nonce
        case identityToken
        case identityTokenString
    }

    private let completion: CompletionHandler
    private var authorizationController: ASAuthorizationController?

    init(completion: @escaping CompletionHandler) {
        self.completion = completion
    }

    private var currentNonce: String?

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

        return hashString
    }

    func signIn(viewController: UIViewController) {
        let nonce = randomNonceString()
        currentNonce = nonce

        let request = ASAuthorizationAppleIDProvider().createRequest()
        request.requestedScopes = [
            .fullName, .email
        ]
        request.nonce = sha256(nonce: nonce)

        let authorizationController = ASAuthorizationController(authorizationRequests: [request])
        authorizationController.presentationContextProvider = viewController.view.window
        authorizationController.delegate = self
        authorizationController.performRequests()

        self.authorizationController = authorizationController
    }

    // Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
    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)

                guard errorCode == errSecSuccess else {
                    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
    }
}

extension AppleSignInProvider: ASAuthorizationControllerDelegate {
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        do {
            guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential else {
                throw AuthError.credential
            }

            guard let nonce = currentNonce else {
                throw AuthError.nonce
            }

            guard let appleIDToken = appleIDCredential.identityToken else {
                throw AuthError.identityToken
            }

            guard let idTokenString = String(data: appleIDToken, encoding: .utf8) else {
                throw AuthError.identityTokenString
            }

            let credential = OAuthProvider.credential(withProviderID: "apple.com", idToken: idTokenString, rawNonce: nonce)
            completion(.success(credential))

        } catch {
            completion(.failure(error))
        }
    }

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

My delegate methods are called when the view controller is set as delegate, but that is not a fix for my issue.

Replies

Nevermind, it was a weak referencing issue.

  • How did you solve?

  • I'm getting this same issue. Upon authentication, the "Do you want to sign in with your Apple ID" dialog dismisses with a strange animation where it pops up first and then down, and the presentationAnchor(for controller: ASAuthorizationController) is never called. There is no weak referencing issue that I can identify.

Add a Comment

I also encountered the same problem. Finally solved. presentationAnchor. It does not call, but it does not affect the process. Added a request. ASAuthorizationPasswordProvider().createRequest() There will be no animation bugs

 let appleIDProvider = ASAuthorizationAppleIDProvider()
 let request = appleIDProvider.createRequest()
 request.requestedScopes = [.fullName, .email]
      
 let authorizationController = ASAuthorizationController(authorizationRequests: [request, ASAuthorizationPasswordProvider().createRequest()])