onmyway133 / blog

šŸ What you don't know is what you haven't learned
https://onmyway133.com/
MIT License
679 stars 33 forks source link

How to sign in with Apple and Firebase and Supabase #977

Open onmyway133 opened 3 months ago

onmyway133 commented 3 months ago

Show ASAuthorizationController with a simple nonce. Once we have the idToken, create an OAuthProvider.appleCredential and pass to Firebase Auth

final class AppleLoginService: NSObject {
    static let shared = AppleLoginService()

    private var nonce: String?

    func show() {
        let nonce = generateNonce()
        self.nonce = nonce

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

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

    private func generateNonce() -> String? {
        "0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._"
            .shuffled()
            .description
    }
}

extension AppleLoginService: ASAuthorizationControllerDelegate {
    func authorizationController(
        controller: ASAuthorizationController,
        didCompleteWithAuthorization authorization: ASAuthorization
    ) {
        guard
            let appleCredential = authorization.credential as? ASAuthorizationAppleIDCredential,
            let idTokenData = appleCredential.identityToken,
            let idToken = String(data: idTokenData, encoding: .utf8)
        else {
            return
        }

        let credential = OAuthProvider.appleCredential(
            withIDToken: idToken,
            rawNonce: nonce,
            fullName: appleCredential.fullName
        )

        Task {
            do {
                let result = try await Auth.auth().signIn(with: credential)
            } catch {
                printD(error)
            }
        }
    }

    func authorizationController(
        controller: ASAuthorizationController,
        didCompleteWithError error: any Error
    ) {
        printD(error)
    }
}

extension AppleLoginService: ASAuthorizationControllerPresentationContextProviding {
    func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
        UIApplication.shared.activeWindow!
    }
}

If we're using Supabase, we can call signInWithIdToken with .apple provider

supabase.auth.signInWithIdToken(
    credentials: .init(
        provider: .apple,
        idToken: idToken,
        nonce: nonce
    )
)

Read more