AppAuth-iOS icon indicating copy to clipboard operation
AppAuth-iOS copied to clipboard

Confirm alert issue : pops up and disappears / "Attempting to load the view of a view controller while it is deallocating"

Open Trecobat opened this issue 5 years ago • 10 comments

Everything works fine on first connection. Then, once authorization expires, authentication process starts again and is ok until the confirm alert : the alert "confirm you want to sign in..." shows up but disappears fastly, and I'm getting the error : "[Warning] Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior (<SFAuthenticationViewController: 0x10e032200>)" I'm guessing it's a delay question but I can't find a way to solve this. Did anyone already faced and solved this issue ? I'm on XCode 11.5, ios 13, using cocoaPod

Trecobat avatar Jun 11 '20 08:06 Trecobat

Hello! Im having the same issue, please check this thread #447. Some apps fix this problem updating to AppAuth 1.2.0 , for instance: airmap auth issue

Enviroment: cocoapod XCode 11.5 IOs 13.5

AsmisAlan avatar Jun 23 '20 12:06 AsmisAlan

It sounds like you're releasing your reference to the object. This may happen if you don't retain a copy of the object returned by this method:

https://github.com/openid/AppAuth-iOS/blob/df840e881d2f9d80c8af037c6acf9573175ecaff/Source/AppAuthCore/OIDAuthState.h#L132-L135

WilliamDenniss avatar Jun 24 '20 22:06 WilliamDenniss

@WilliamDenniss Thanks for your answer, but I'm not sure I understood well, could you be more specific ? What should I do to retain a copy of this object and where should I make a call to it ?

Trecobat avatar Jan 06 '21 12:01 Trecobat

@Trecobat I was able to solve this issue by explicitly putting my bundle identifier in the URL Schemes in the Info.plist. instead of '${PRODUCT_BUNDLE_IDENTIFIER}' try actually writing it out : 'com....'

stubuchbinder79 avatar Apr 27 '21 18:04 stubuchbinder79

this view controller warning issue is caused by one of the objects you use to create your authorisation request or endsession request being local to the function. The function ends so any variable created inside are deallocated but the webview is shown on another thread so cant find your object and shows this warning and the alert appears and disappears.

for endSession possible objects causing the issue are OIDExternalUserAgentIOS or OIDEndSessionRequest dont use if let to create these.


//wrong agent is local var will be deallocated before webview presented asynchronously
                   if let agent: OIDExternalUserAgent = OIDExternalUserAgentIOS(presenting: self) {

//wrong endSessionRequest is local var will be deallocated before webview presented asynchronously
                        if let endSessionRequest = OIDEndSessionRequest(configuration: configuration,
                                                            idTokenHint: kTestIdTokenHint,
                                                            postLogoutRedirectURL: postLogoutRedirectURL,
                                                            additionalParameters: [:]) {

//will throw error as this shows webview asych so endSessionRequest/ agent may be deallocated as their local vars and this method on main thread may have ended and deallocated them
                            OIDAuthorizationService.present(endSessionRequest,
                                                            externalUserAgent: agent) { (response, error) in
                                ....
                            }
                        }else{
                            print("endSessionRequest is nil")
                        }

                    }else{
                        print("OIDExternalUserAgentIOS(presenting: self) is nil")
                    }

OIDAuthorizationService.present(...) will show the webview on a seperate thread but the method with this code in it will end first and dealloc endSessionRequest and agent

make them ivars outside the method create them first then call the OIDAuthorizationService.present...

class CLKOpenIdLoginViewController: UIViewController {

    var endSessionRequest: OIDEndSessionRequest?
    var userAgent:OIDExternalUserAgentIOS?
    
    func endSession(){
        print("endSession")
        //save as ivar so its not deallocated when this method ends
        self.userAgent = OIDExternalUserAgentIOS(presenting: self)
        
        if let configuration = self.configuration {
            if let _ = configuration.endSessionEndpoint {
                let kTestIdTokenHint = "id-token-hint"
                let postLogoutRedirectURLString = "WEBPAGETOSHOWAFTERLOGOUT"

                if let postLogoutRedirectURL = URL(string: postLogoutRedirectURLString) {
                    //save as ivar so its not deallocated when this method ends
                    endSessionRequest = OIDEndSessionRequest(configuration: configuration,
                                                            idTokenHint: kTestIdTokenHint,
                                                            postLogoutRedirectURL: postLogoutRedirectURL,
                                                            additionalParameters: [:])
                    //------------------------------------------------------------------------------------------
                   //ok uses ivar wont be dealloc when endSession() method ends
                    if let userAgent = self.userAgent {
                        //ok uses ivar wont be dealloc when endSession() method ends
                        if let endSessionRequest = endSessionRequest {
                            OIDAuthorizationService.present(endSessionRequest,
                                                            externalUserAgent: userAgent) { (response, error) in
                                if let error = error
                                {
                                    logger.error("endSessionRequest: error:\(error)")

                                }else{
                                    if let response = response
                                    {
                                        print(response)

                                    }else{
                                        logger.error("endSessionRequest is nil")
                                    }
                                }
                            }
                        }else{
                            logger.error("endSessionRequest is nil")
                        }

                    }else{
                        logger.error("self.userAgent is nil")
                    }
                }else{
                    logger.error("URL(string: postLogoutRedirectURLString) is nil")
                }
            }else{
                logger.error("configuration.endSessionEndpoint is nil")
            }
        }else{
            logger.error("self.configuration is nil")
        }
    }

clearbrian avatar Jun 15 '21 16:06 clearbrian

After months struggling with this issue, I finally worked it out, thanks to this : https://curity.io/resources/learn/swift-ios-appauth/#get-the-code (thanks for that great example) which shows how to get OIDErrorCode.userCanceledAuthorizationFlow when user clicks on "cancel" I also subscribed to a notification in my controller : UIApplication.didBecomeActiveNotification and call my login function from the callback, when i'm sure the app is loaded as it should. Hope it can help :)

Trecobat avatar Oct 20 '22 06:10 Trecobat