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;
}
}