Flutter App using flutter_appauth to Authenticate with IdentityServer4 Is Stuck in Endless Login Cycle

1.2k Views Asked by At

We are writing a new mobile app using Flutter. At the moment we are concentrating on Android and want to use IdentityServer4 to handle user authentication. We are new to both Flutter, and IdentityServer4 (and OAuth for that matter). However, we've built the IdentityServer4 server along with the standard sample Weather Forecast Blazor app and we can successfully login.

So, we move to the Android app. We decided to use flutter_appauth to handle the interactions with IdentityServer4. We started using the example which usefully also uses IdentityServer. We had to make various changes to get the app working but it works and proves that flutter_appauth and IdentityServer4 work together, and after a user logs in they are correctly returned to the app.

So then we pointed the flutter app to our IdentityServer4. This required us to change the manifestPlaceholder in the app's build.gradle (android\app\build.gradle)

manifestPlaceholders += [appAuthRedirectScheme: 'com.mysite.oauthsample']

We made sure that redirectUrl used in the AuthorizationRequest matched with the manifestPlaceholder

redirectUrl = 'com.mysite.oauthsample://oauthredirect';

We made sure that the above redirectUrl was set up in the ClientRedirectUri table in IdentityServer4 for the client in question.

When we run the app and select the SignInWithAutoCodeExchange button we are correctly directed to the login page of our IdentityServer4. When we login successfully the server shows us a "You are now being returned to the application." But instead of returning to the application it kind of flickers another page/screen then returns to the Login page. The user is then stuck on the Login page and cannot naturally return to the app. Closing the Login page by using the [x] button raises an exception that is caught by the flutter app which indicates "User cancelled flow" (well, I guess the user did cancel the flow by clicking the [x] button - so no issues there).

Does anyone have any idea what we may have done (or not done) to cause this endless login loop. We did have a lot of issues with the redirectUrl and manifestPlaceholder which caused invalid_request errors on the IdentityServer but we seem to have resolved these; although I can't categorically rule that out.

Here is our configuration setup: -

_clientId = 'flutter'
_clientSecret = '';
 _redirectUrl = 'com.mysite.oauthsample://oauthredirect';
_issuer = 'https://ouridentityserver.azurewebsites.net';
_discoveryUrl = 'https://ouridentityserver.azurewebsites.net/.well-known/openid-configuration';
_postLogoutRedirectUrl = 'com.mysite.oauthsample://oauthredirect';

_serviceConfiguration = const AuthorizationServiceConfiguration(
  authorizationEndpoint: 'https://ouridentityserver.azurewebsites.net/connect/authorize',
  tokenEndpoint: 'https://ouridentityserver.azurewebsites.net/connect/token',
  endSessionEndpoint: 'https://ouridentityserver.azurewebsites.net/connect/endsession',

Here is the code that is called when the button is clicked: -

  Future<void> _signInWithAutoCodeExchange(
      {bool preferEphemeralSession = false}) async {
    try {
      _setBusyState();

      // show that we can also explicitly specify the endpoints rather than getting from the details from the discovery document
      final AuthorizationTokenResponse? result =
          await _appAuth.authorizeAndExchangeCode(
        AuthorizationTokenRequest(
          _clientId,
          _redirectUrl,
          clientSecret: _clientSecret,
          serviceConfiguration: _serviceConfiguration,
          scopes: _scopes,
          preferEphemeralSession: preferEphemeralSession,
        ),
      );

      // this code block demonstrates passing in values for the prompt parameter. in this case it prompts the user login even if they have already signed in. the list of supported values depends on the identity provider
      // final AuthorizationTokenResponse? result = await _appAuth.authorizeAndExchangeCode(
      //   AuthorizationTokenRequest(_clientId, _redirectUrl,
      //       serviceConfiguration: _serviceConfiguration,
      //       scopes: _scopes,
      //       promptValues: ['login']),
      // );

      if (result != null) {
        _processAuthTokenResponse(result);
        await _testApi(result);
      }
    } catch (err) {
      _clearBusyState();
    }
  }
0

There are 0 best solutions below