Flutter access BloC without Context

Viewed 34

I have a problem with my BloC provider in one of my Flutter applications. I use Chopper as HTTP client and it creates a Chopper instance right at the beginning of the app which I then inject with get_it wherever I want to fetch data from my API. In the meantime I have implimented a ChopperAuthenticator which fetches a new token from the API when the old one expires (statuscode 401). But the problem is, if the refresh-token is expired too, the user should be logged out. For this I just check if the fetching of the refresh-token was successful, if this is not the case my Authentication BloC should be notified that the user is not logged in anymore.

But I can't call BlocProvider.of<AuthenticationBloc>(context).add(Logout()); because in the chopper instance the build context is not known. Is there another way to change the state of a BloC? Do you have any ideas how I can rebuild the whole thing to make it work?

FlutterSecureStorage storage = locator.getIt<FlutterSecureStorage>();
UserRepository userRepository = locator.getIt<UserRepository>();

Swagger getClient(String baseUrl) {
  return Swagger.create(
    baseUrl: baseUrl,
    authenticator: ChopperAuthenticator(),
    interceptors: [
      MobileDataInterceptor(),
      const HeadersInterceptor(
        {
          'content-type': 'application/json',
          'Accept': 'application/json',
        },
      ),
      HttpLoggingInterceptor(),
      (Response response) async {
        return response;
      },
      (Request request) async {
        final String? token = await storage.read(key: 'accessToken');
        if (token != null && !request.url.contains('refresh')) {
          final Map<String, String> map = {'authorization': 'Bearer $token'};
          request.headers.addAll(map);
        }
        return request;
      },
    ],
  );
}

class ChopperAuthenticator extends Authenticator {
  @override
  FutureOr<Request?> authenticate(
    Request request,
    Response<dynamic> response, [
    Request? originalRequest,
  ]) async {
    if (response.statusCode == 401) {
      final String? refreshToken = await storage.read(
        key: 'refreshToken',
      );
      final String? accessToken = await storage.read(
        key: 'accessToken',
      );
      final Response newResponse =
          await userRepository.apiClient.apiAuthenticateRefreshTokenPost(
        body: RefreshRequestDTO(
          accessToken: accessToken,
          refreshToken: refreshToken,
        ),
      );

      if (newResponse.isSuccessful) {
        await storage.write(
          key: 'accessToken',
          value: newResponse.body['accessToken'].toString(),
        );
        await storage.write(
          key: 'refreshToken',
          value: newResponse.body['refreshToken'].toString(),
        );
        String? newToken = newResponse.body['accessToken'].toString();
        final Map<String, String> updatedHeaders =
            Map<String, String>.of(request.headers);

        newToken = 'Bearer $newToken';
        updatedHeaders.update(
          'Authorization',
          (String _) => newToken!,
          ifAbsent: () => newToken!,
        );
        debugPrint('Token renewed');
        return request.copyWith(headers: updatedHeaders);
      } else {
        <Here should be the logic to log out the user>
      }
    }
    return null;
  }
}
0 Answers
Related