iosflutteridentityserver4appauth

Calling AppAuth sign out / endsession endpoint using IdentityServer4 in Flutter on iOS


I am using the flutter_appauth package in Flutter to handle authorization code flows against IdentityServer4 and have been unable to find a method by which to call the /endsession endpoint in iOS.

To get an idea of what I'm trying to do, this is my working Android implementation using the url_launcher package:

    var signOutUrl = '${_endSessionUrl}?id_token_hint=${_idToken}&post_logout_redirect_uri=${AppConfig.oidcCallbackUri}';
    await launch(signOutUrl);

Using the same code, iOS just reports a general PlatformException with no additional detail as to the cause, though the exception is surely related to bypassing AppAuth entirely by just attempting to launch a url.

The solution in this GitHub comment appears to work using OKTA, but when using IdentityServer4, I'm getting the following exception which immediately terminates the Flutter app:

[DEVICE LOG] 2020-04-16 08:55:01.039163-0400  localhost Runner[18007]: (CoreFoundation) *** Terminating app due to uncaught exception 'Attempted to create a token exchange request from an authorization
response with no authorization code.', reason: 'Attempted to create a token exchange request from an authorization response with no authorization code.'

This seems to make sense considering that my /endsession endpoint isn't returning an authorization response.

In any event, the solution of calling an authorization endpoint with an endsession URL is a hack at best, but it seems to be the "accepted" way of doing this.

All of the documentation I can find surrounding using AppAuth says that signout can be achieved by just "forgetting" tokens in-app, but since the browsers retain auth cookies, signing back in happens automatically. Users don't have a chance to pick a different account.

Also worth noting is that this is not specific to Flutter, the flutter_appauth package, or IdentityServer4. This comment on the native AppAuth-iOS package lays out the same issue with the same solution as outlined above.

It absolutely must be possible to sign out (and thus delete the browser cookies) on iOS, but I'm at a complete loss as to how to achieve it.


Solution

  • When you call method for authorizing and exchanges code, there is needed to add an additional parameter called "promptValues" with 'login' value. In this way, every time the login is made there is no value in the cache and it always asks for a new login.

    I came to this solution from this post openid/AppAuth-Android#215 where it was commented about Logout and Delete browser history and OpenId docs

    final AuthorizationTokenResponse result =
    await appAuth.authorizeAndExchangeCode(
      AuthorizationTokenRequest(
        your_client_id,
        your_localhost,
        promptValues: ['login'],
        discoveryUrl:
        your_discovery_url,
        scopes: [your_scopes],
      ),
    );