openid / openid/AppAuth-iOS

Logout / End Session works only partially (not for broker login)

Open
#616 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Objective-C
Stars
2k
Forks
867
Avg merge
4d 48m
Merged PRs (30d)
1

Description

We have apps for both iOS and Android. For both of these we use AppAuth to handle our authentication.
Our Auth Server is Keycloak.

For Android the logout / end session works as expected and for iOS it doesn't (even though I think only here in the iOS library is code to even implement the logout).

Problem
The logout works (success response from keycloak) and we are even logged out from keycloak but not from the "third-party" broker which the user used to login.

Here's some log statements from keycloak to see what I mean:

iOS:
image

Android:
image

As you can see for android and iOS first the same logout call happens (except that for iOS the id_token_hint is also sent and for android only the redirect_uri).
But then iOS stops and does not logout from the other realms / the broker.

We implemented iOS like in this issue: https://github.com/openid/AppAuth-iOS/issues/255

Our code:

    @objc func logout(_ call: CAPPluginCall) {
        guard let authState = self.loadAuthState() else {
            return;
        }

        guard let url = call.getString("url") else {
            call.error("Missing or invalid URL configuration")
            return;
        }

        let authorizationEndpoint = URL(string: url + "/auth")!
        let tokenEndpoint = URL(string: url + "/token")!
        let logoutEndpoint = URL(string: url + "/logout?redirect_uri=<myRedirectUri>")!

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

        guard let idToken = authState.lastTokenResponse?.accessToken else {
            return;
        }

        let request = OIDEndSessionRequest(configuration: configuration,
                                           idTokenHint: idToken,
                                           postLogoutRedirectURL: URL(string: "<myRedirectUri>")!,
                                           state: (authState.lastAuthorizationResponse.state!),
                                           additionalParameters: nil);

        let agent = OIDExternalUserAgentIOS(presenting: self.bridge.viewController)

        Self.currentAuthorizationFlow = OIDAuthorizationService.present(request, externalUserAgent: agent!) {response, error in
            guard let _ = response, error == nil else {
                print("Authorization error: \(error?.localizedDescription ?? "Unknown error")")
                call.error("Authorization error");
                return
            }

            self.storeAuthState(authState: nil);
            call.success();
        }
    }

=> we already tried various things here:

  • not sending the id_hint
  • doing a manually HTTP request to the logout URL (so we can do the exact same request as in android)
  • other variations of the code above, from the linked issue...

And here (just for the sake of completeness) the code we use for android (where it works):

  @PluginMethod()
  public void logout(final PluginCall call) {
    try {
      // the library doesn't yet support a logout, so we just clear the cache and then manually call the logout endpoint
      this.clearCache(call);

      // reference: https://github.com/openid/AppAuth-Android/pull/433#issuecomment-617031510
      String url = call.getString("url");

      Uri endSessionEndpointURI = Uri.parse(url + "/logout?redirect_uri=" + redirectUrl);
      AuthorizationService authService = new AuthorizationService(this.bridge.getActivity());

      CustomTabsIntent.Builder intentBuilder = authService.createCustomTabsIntentBuilder(endSessionEndpointURI);
      CustomTabsIntent customTabsIntent = intentBuilder.build();
      customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
      customTabsIntent.intent.setData(endSessionEndpointURI);

      saveCall(call);
      startActivityForResult(call, customTabsIntent.intent, RC_LOGOUT);
    } catch (Exception ex) {
      call.error(ex.toString());
    }
  }

Note that both our apps are built with capacitor (https://capacitorjs.com/).

Does anyone have any idea what the problem could be here?
My personal suspicion is that it has something to do with how iOS stores session infos / cookies and stuff like that and that the login call happens in a different "session" (ASWebAuthenticationSession?) or something like that.

Any help would be greatly appreciated.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reported logout entry points using OIDEndSessionRequest, OIDExternalUserAgentIOS, and the Android custom-tab flow, then review the linked AppAuth-iOS issue 255. Reproduce logout through a Keycloak broker and compare the iOS and Android requests and session behavior; done means the broker session is also ended on iOS.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, ios, java, swift
Domain
authentication, mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.