openid / AppAuth-iOS

iOS and macOS SDK for communicating with OAuth 2.0 and OpenID Connect providers.
https://openid.github.io/AppAuth-iOS
Apache License 2.0
1.77k stars 773 forks source link

Logout function not working on iOS > 14 #655

Closed luca8846 closed 1 year ago

luca8846 commented 3 years ago

Hello, I'm experiencing an issue on iOS > 14. The logout function "OIDEndSessionRequest" isn't working correctly and I can't complete the logout procedure.

This is my code:

let config = OIDServiceConfiguration(authorizationEndpoint: URL(string: AUTHORIZATION_ENDPOINT)!, tokenEndpoint: URL(string: TOKEN_ENDPOINT)!, issuer: URL(string: ISSUER)!, registrationEndpoint: URL(string: REGISTRATION_ENDPOINT)!, endSessionEndpoint: URL(string: END_SESSION_ENDPOINT)!)

let logoutRequest = OIDEndSessionRequest(configuration: config, idTokenHint: (authState?.lastTokenResponse?.refreshToken)!, postLogoutRedirectURL: URL(string: "REDIRECT_URI")!, state: (authState?.lastAuthorizationResponse.state)!, additionalParameters: nil)

let storyboard = UIStoryboard(name: "Main", bundle: nil) let vc = storyboard.instantiateViewController(withIdentifier: "myView") as! MyViewController

let userAgent = OIDExternalUserAgentIOS(presenting: vc)

OIDAuthorizationService.present(logoutRequest, externalUserAgent: userAgent!, callback: { (authorizationState, error) in })

The error code received is: "Error Domain=org.openid.appauth.general Code=-3"

Can you help me please?

Thanks in advance

lehelmedves commented 3 years ago

I am using a similar code, the difference being that I'm passing the idToken to the OIDEndSessionRequest instead of the refreshToken. The out come is still not the desired one - the server logs me out however the authentication sheet is not closed and I do not get any kind of callback.

Does anyone have any idea why this is so?

Kerstin2020 commented 2 years ago

As a workaround, you can use a "RP-Initiated Logout" instead. This is a get request to the end session endpoint and ID token as query param. This will also logout and end the session without showing the authentication sheet

lehelmedves commented 2 years ago

Indeed, but my main problem with this is, that this way the cookie will not be erased and upon the next login this will be seen by the user.

EggYoke commented 2 years ago

We are in a similar predicament as the OP. We call the the OIDEndSessionRequest the same way but here is what happens after that.

We are presented with an alert that's named Sign-in. We saw that others had this issue and that there's no way to correct that outside of AppAuth. So we are not too concerned about this and tap the Continue button.

We are then presented with a logout page where we are asked to tap the Sign out button. Tapping the button updates the page now displaying You are now signed out. Here's the problem: The page is never dismissed and the session callback is never called. Only by tapping the Cancel button at the top of the screen will we get the error: Error Domain=org.openid.appauth.general Code=-3 "(null)" UserInfo={NSUnderlyingError=0x600000438450 {Error Domain=com.apple.AuthenticationServices.WebAuthenticationSession Code=1 "(null)"}}

Any help would be greatly appreciated!

lehelmedves commented 2 years ago

@EggYoke this seems to be a redirect URI issue, it needs to be specified on the identity server and the same needs to be used when you perform the end session request.

janmenjayarout commented 2 years ago

Hello All, I am facing an annoying issue while trying to logout from the AppAuth/OpenId session in iOS.

1 - On click of logout button the alert is appearing and dismissing immediately 2 - No error code appearing in console now (earlier i was getting same error as of @EggYoke but I corrected that after putting the registration URL as ${MybaseURL}/v1/clients) 3 - But my problem is when I am logging in again, the login UI is not presented to user (not even getting any callback response from presentEndSessionRequest method), rather the previous user's session is coming back (Seems not logging out earlier user)

Can anyone put some light, how to fix this.. (I researched a lot but no luck)

Here is my Logout Code

NSString *kClientID = @"**********";
    NSURL *kRedirectURI = [NSURL URLWithString:@"*******"]; //Login Redirect URI
    NSURL *authorizationEndpoint = [NSURL URLWithString:@"*************/v1/authorize"];
    NSURL *tokenEndpoint = [NSURL URLWithString:@"***************/v1/token"];

    NSURL *urlIssuer = [NSURL URLWithString:@"****************"];
    NSURL *urlRegistration = [NSURL URLWithString:@"*****************/v1/clients"];
    NSURL *urlSessionEndPoint = [NSURL URLWithString:@"*******************/v1/logout"]; //Logout Redirect URI

    configuration = [[OIDServiceConfiguration alloc] initWithAuthorizationEndpoint:authorizationEndpoint tokenEndpoint:tokenEndpoint issuer:urlIssuer registrationEndpoint:urlRegistration endSessionEndpoint:urlSessionEndPoint];

    NSURL *logoutURL = [NSURL URLWithString:@"***********"];
    NSDictionary *additionalParam = nil;

    OIDEndSessionRequest *endSessionRequest = [[OIDEndSessionRequest alloc] initWithConfiguration:configuration idTokenHint:self.authState.lastTokenResponse.refreshToken postLogoutRedirectURL:logoutURL additionalParameters:additionalParam];

    OIDExternalUserAgentIOS *iOSExternalAgent = [[OIDExternalUserAgentIOS alloc] initWithPresentingViewController:self];

    [OIDAuthorizationService presentEndSessionRequest:endSessionRequest externalUserAgent:iOSExternalAgent callback:^(OIDEndSessionResponse * _Nullable endSessionResponse, NSError * _Nullable error) {

        if (endSessionResponse) {

            for (NSHTTPCookie *cookie in [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies) {
                [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
            }
        } else {
            MPLogs(@"Error: %@", error.description);

        }
    }];
Itsprobme commented 2 years ago

@EggYoke was there any work around to fix the logout issue?

Itsprobme commented 2 years ago

@WilliamDenniss is there any workaround for this?

EggYoke commented 2 years ago

We have a solution for our issue. We figured out that the OIDEndSessionRequest's idTokenHint parameter needs the idToken and not a refreshToken.

Itsprobme commented 2 years ago

@EggYoke how did you get the idToken?

vuta1927 commented 2 years ago

Hi @EggYoke, did that help to resolve the problem "alert that's named Sign-in" ?

softsan commented 1 year ago

@EggYoke How did you manage to close the browser window when you sign out? Becuase i have same issue and i double checked that i passed idToken in IdTokenHint, but it the browser window still remains open.

tiwari1amrit commented 1 year ago

@softsan Did you solve this issue?

Zachthac commented 1 year ago

Any updates on this?

tiwari1amrit commented 1 year ago

@Zachthac I found a solution, please have a look.

    private var externalUserAlertSession: OIDExternalUserAgentSession!

    public func logout(onSuccess: (() -> Void)? = nil) {

        guard let userDetailData = UserDefaults.hydraUserDetail else {
            return
        }

        let inksAuthLoginModel = InksAuthLoginModel.fromDictionary(userDetailData)

        let logoutEndpointString = Urls.Hydra.logout() + "/?redirect_uri=" + Urls.Hydra.redirectCallbackURL()

        let logoutEndpoint = URL(string: logoutEndpointString)!

        let configuration = OIDServiceConfiguration(
            authorizationEndpoint: authEndpoint,
            tokenEndpoint: tokenEndpoint,
            issuer: nil,
            registrationEndpoint: nil,
            endSessionEndpoint: logoutEndpoint)

        guard let idToken = inksAuthLoginModel.idToken else {
            return
        }

        let endSessionRequest = OIDEndSessionRequest(
            configuration: configuration,
            idTokenHint: idToken,
            postLogoutRedirectURL: redirectURL,
            state: inksAuthLoginModel.state ?? "",
            additionalParameters: nil)

        let agent = OIDExternalUserAgentIOS(presenting: viewController)

        self.externalUserAlertSession = OIDAuthorizationService.present(
            endSessionRequest,
            externalUserAgent: agent!) {[weak self] response, error in
                guard let `self` = self else { return }

                if let error = error {
                    print("Authorization error: \(error.localizedDescription)")
                    return
                }

                guard let response = response else {
                    print("Authorization response is nil.")
                    return
                }

                print("Authorization response: \(response)")

                HTTPCookieStorage.shared.cookies?.forEach { cookie in
                    HTTPCookieStorage.shared.deleteCookie(cookie)
                }

                UserDefaults.standard.flushAllSaveData()

                onSuccess?()
            }
    }
mdmathias commented 1 year ago

I'm closing this to de-clutter our issue backlog since this doesn't appear to be a bug.