How to retrieve a new token with a refresh token in flutter in a ferry (graphql) client?
The response after a mutation looks like this:
{
"data": {
"auth_login": {
"access_token": "ey...",
"refresh_token": "Ua...",
"expires": 900000
}
}
}
I tried to accomplish it with fresh_graphql, but it does not work. The authenticationStatus is always unauthenticated but the token was always legit.
Implementation:
import 'dart:math';
import 'package:ferry/ferry.dart';
import 'package:ferry_hive_store/ferry_hive_store.dart';
import 'package:fresh_graphql/fresh_graphql.dart';
import 'package:gql_http_link/gql_http_link.dart';
import 'package:hive/hive.dart';
Future<Client> initClient(String? accessToken, String? refreshToken) async {
Hive.init('hive_data');
final box = await Hive.openBox<Map<String, dynamic>>('graphql');
await box.clear();
final store = HiveStore(box);
final cache = Cache(store: store);
final freshLink = await setFreshLink(accessToken ?? '', refreshToken);
final link = Link.from(
[freshLink, HttpLink('https://.../graphql/')]);
final client = Client(
link: link,
cache: cache,
);
return client;
}
Future<FreshLink> setFreshLink(String accessToken, String? refreshToken) async {
final freshLink = FreshLink<dynamic>(
tokenStorage: InMemoryTokenStorage<dynamic>(),
refreshToken: (dynamic token, client) async {
print('refreshing token!');
await Future<void>.delayed(const Duration(seconds: 1));
if (Random().nextInt(1) == 0) {
throw RevokeTokenException();
}
return OAuth2Token(
accessToken: 'top_secret_refreshed',
);
},
shouldRefresh: (_) => Random().nextInt(2) == 0,
)..authenticationStatus.listen(print);
print(freshLink.token);
print(freshLink.authenticationStatus);
await freshLink
.setToken(OAuth2Token(tokenType: 'Bearer', accessToken: accessToken));
return freshLink;
}
Any solution, even without fresh_graphql, would be appreciated!
The way I initialize my ferry client is as follows.
Create a CustomAuthLink that inherits from AuthLink.
import 'package:gql_http_link/gql_http_link.dart';
class _CustomAuthLink extends AuthLink {
_CustomAuthLink() : super(
getToken: () {
// ...
// Call your api to refresh the token and return it
// ...
String token = await ... // api refresh call
return "Bearer $token"
}
);
}
Use this custom auth link to initialise your client.
...
final link = Link.from([freshLink, HttpLink('https://.../graphql/')]);
...
Client(
link: _CustomAuthLink().concat(link),
)
...
I am not sure if you still going to need freshLink anymore. You might wanna remove it and pass HttpLink(...)
directly into the .concat(...)
method.