Search code examples
swiftswiftuioauth-2.0azure-ad-msal

Trying to do MSAL OAuth2.0 but the acquire token is not completing despite authentication completing?


So I followed this link which is a sample project implementing MSAL with Swift/SwiftUI. Some odd reason, I am at the error where the Microsoft popup shows up, login works as intended, but now the popup doesn't dismiss or the completion of the acquireToken doesn't launch. The code I have below is a slightly modified to be more similar to a working signInWithGoogle() function but I have tried being identical to the GitHub repo in the guide but to no avail.

    // MARK: Google OAuth2.0 which works perfectly
    func signinWithGoogle() {
        let scenes = UIApplication.shared.connectedScenes
        let windowScene = scenes.first as? UIWindowScene
        let window = windowScene?.windows.first

        guard let presentingViewController = window!.rootViewController else {
            print("There is no root view controller!")
            return
        }

        GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: presentingViewController) { user, error in
            guard error == nil else { return }
            guard let user = user else { return }

            user.authentication.do { authentication, error in
                guard error == nil else { return }
                guard let authentication = authentication else { return }

                let idToken = authentication.idToken
                self.verifyEmail(idToken: idToken!)
            }
        }
    }


    // MARK: Microsoft MSAL which doesn't work
    func signInWithMicrosoft() {
        let scenes = UIApplication.shared.connectedScenes
        let windowScene = scenes.first as? UIWindowScene
        let window = windowScene?.windows.first

        guard let presentingViewController = window!.rootViewController else {
            print("There is no root view controller!")
            return
        }
        
        do {
            let authority = try MSALB2CAuthority(url: URL(string: "https://login.microsoftonline.com/TENANT_ID_HERE")!)
            let pcaConfig = MSALPublicClientApplicationConfig(clientId: "CLIENT_ID_HERE", redirectUri: "REDIRECT_URI_HERE", authority: authority)
            let application = try MSALPublicClientApplication(configuration: pcaConfig)
            let webViewParameters = MSALWebviewParameters(authPresentationViewController: presentingViewController)
            let interactiveParameters = MSALInteractiveTokenParameters(scopes: ["user.read"], webviewParameters: webViewParameters)
            interactiveParameters.promptType = MSALPromptType.selectAccount
            
            application.acquireToken(with: interactiveParameters) { (result, error) in
                print("DEBUG: THIS COMPLETION DOESN'T RUN WHEN SUCCESSFULLY LOGGED IN, BUT CLOSING THE MICROSOFT LOGIN DOES RUN THIS COMPLETION")
                
                guard let result = result else {
                    print("error \(error?.localizedDescription)")
                    return
                }
                
                if let account = result.account.username {
                    print("logging \(account)")
                    print("logging \(result.account.description)")
                    UIApplication.shared.windows.first {
                        $0.isKeyWindow
                    }!.rootViewController = UIHostingController(rootView: ContentView())
                }
            }
        } catch {
            print("\(#function) logging error \(error)")
        }

I have the above in an EmailVerificationViewModel instantiated typically in an EmailVerificationView()

@StateObject var emailVerificationVM = EmailVerificationViewModel()

And I have a button that calls the function like so,

Button {
    emailVerificationVM.signInWithMicrosoft()
} label: {
    Text("Login")
}

Tapping the button does open the Microsoft Office login as expected; however, after completing the authentication, some reason the completion block of the application.acquireToken(with: interactiveParameters) DOESN'T EXECUTE. However, it does execute with an error when closing out of the Microsoft sign in popup as desire so the completion block runs on an "error" but not when the authentication completes. Has anyone implemented Microsoft OAuth2.0 in Swift/SwiftUI? I feel like this is a typical thing, but so many different solutions just aren't working.

Here is a GIF of me testing MSAL


Solution

  • The issue was that Azure was set up incorrectly to handle web logins and not an app login. The redirect URI should be something related to the app and not an actual weblink if set up correctly for iOS.