Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PlatformException(token_failed, Concurrent operations detected: token, token, null, null) #224

Closed
endritgojanikodelabs opened this issue Jul 8, 2021 · 9 comments

Comments

@endritgojanikodelabs
Copy link

endritgojanikodelabs commented Jul 8, 2021

When I am refreshing the token

 final TokenResponse result = await _appAuth.token(TokenRequest(
          _clientId, _redirectUrl,
          refreshToken: _refreshToken,
          discoveryUrl: _discoveryUrl));

I am getting this error only on Android:
PlatformException(token_failed, Concurrent operations detected: token, token, null, null)

@johnggli
Copy link

johnggli commented Jul 16, 2021

I had the same error: PlatformException (PlatformException(token_failed, Concurrent operations detected: token, token, null, null))

this error doesn't happen when I run through the terminal, with the command "flutter run", but it does happen when I run through vscode

@MaikuB
Copy link
Owner

MaikuB commented Jul 18, 2021

This is Android-specific and required with the way Android works. As implied by the error, this would mean your application is making concurrent calls to the plugin where it's not waiting for an operation to finish before starting another one. You would need to check your application to track down where this is happening and address it

@SteveAlexander
Copy link

It would be great if flutter_appauth could serialize access to this API on Android, to avoid this issue.

Otherwise, any apps that do concurrent downloads (or other HTTP access) that involves refreshing tokens (perhaps to different OIDC providers) will need to essentially serialize this access

@florisdipt
Copy link

florisdipt commented Sep 20, 2021

t happen when I run through the terminal, with the command "flutter run", but it does happen when I run through vscode

This is also the case for me. Works on ios, works on android using flutter run but when launching with vscode i encounter the same issue.

My launch.json:

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Flutter",
      "request": "launch",
      "type": "dart"
    },
    {
      "name": "Flutter Release",
      "request": "launch",
      "type": "dart",
      "flutterMode": "release"
    },
    {
      "name": "Debug intergration test",
      "request": "launch",
      "type": "dart",
      "env": {
        "VM_SERVICE_URL": "http://127.0.0.1:59760/"
      },
      "program": "test_driver/app.dart",
      "flutterMode": "debug"
    }
  ]
}

@simon-hypecast
Copy link

Has anyone overcome this issue with this error?

PlatformException(token_failed, Concurrent operations detected: token, token, null, null)

How would a solution to serialize the plug-in access on token refresh looks like?

Any hints someone?

@simon-hypecast
Copy link

simon-hypecast commented Nov 3, 2021

Ok... stumbled over AsyncCache. By now it seems to fix the problem.

@RobertHeim
Copy link

RobertHeim commented Apr 1, 2022

This is also a problem when we run background operations that start their own flutter engine. Syncing these only because of the plugin is cumbersome. AsyncCache does not help in this scenario.

@ahmedkhouaja
Copy link

Any solution Here ?

initAction() async {

setLoadingState();
final bool isAuth = await AuthService.instance.init();
if (isAuth) {
  setState(() {
    isProgressing = false;
    isLoggedIn = true;
    name = AuthService.instance.idToken?.name;

  });
} else {
      isProgressing = false;
}

}

Future init() async {

  final storedRefreshToken = await secureStorage.read(
      key: REFRESH_TOKEN_KEY);

  if (storedRefreshToken == null) {
    return false;
  }

  try {
    final TokenResponse? result = await appAuth.token(
      TokenRequest(
        AUTH0_CLIENT_ID,
        AUTH0_REDIRECT_URI,
        issuer: AUTH0_ISSUER,
        refreshToken: storedRefreshToken,
        clientSecret: CLIENT_SECRET,
      ),
    );
    final String setResult = await _setLocalVariables(result);

    Auth0User user = await getUserDetails(result!.accessToken);
    blMicroappGlobalStore.dispatch(BlMicroappAction(package_name: 'auth',
        state_name: 'auth', action_name: 'AuthUser', payload: user));
    return setResult == 'Success';

  } catch (e, s) {
    print('error on Refresh Token: $e - stack: $s');
  
    return false;
  }

}

PlatformException(token_failed, Concurrent operations detected: token, token, null, null) same error

@karmazinkd
Copy link

In our case this issue appeared on Android because we had multiple Dio clients that used the same Fresh<OAuth2Token> interceptor. That means all these dio clients were trying to refresh the token in the same time, which caused the aforementioned error.
What we did is we added some waiting mechanism, so that when the first dio client starts to refresh the token all other clients wait for it to complete.

This is the interceptor, a singleton:

  @override
  Fresh<OAuth2Token> get authInterceptor {
    if (_authInterceptorInstance != null) {
      return _authInterceptorInstance!;
    } else {
      return _authInterceptorInstance = Fresh.oAuth2(
        tokenStorage: _tokenStorage,
        refreshToken: _queuedRefreshing,
      );
    }
  }

this is the method that prevents refreshing to happen at the same time:

  Future<OAuth2Token>? _refreshingProcess;

  Future<OAuth2Token> _queuedRefreshing(OAuth2Token? refreshToken, Dio dio) async {
    if (_refreshingProcess != null) {
      return _refreshingProcess!;
    }

    _refreshingProcess = _startTokenRefreshing(refreshToken, dio);
    _refreshingProcess!.whenComplete(() {
      _refreshingProcess = null;
    });
    return _refreshingProcess!;
  }

and the actual method for refreshing the token:

Future<OAuth2Token> _startTokenRefreshing(OAuth2Token? refreshToken, Dio dio) async {
  final TokenResponse? tokenResponse = await _appAuth.token(
    TokenRequest(
      AuthConstants.clientId,
      AuthConstants.redirectUrl,
      refreshToken: refreshToken?.refreshToken,
      issuer: AuthConstants.issuer,
      scopes: [AuthConstants.authKeycloakScope],
    ),
  );

  final OAuth2Token oAuth2Token = OAuth2Token(
    accessToken: tokenResponse?.accessToken ?? '',
    refreshToken: tokenResponse?.refreshToken,
    expiresIn: accessTokenExpirationDateTime,
    scope: AuthConstants.authKeycloakScope,
  );

  await _tokenStorage.write(oAuth2Token);
  return oAuth2Token;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants