Flutter: How to refresh token when token expires with ferry (graphql) client?

421

The way I initialize my ferry client is as follows.

  1. 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"
          }
       );
    }
    
  2. Use this custom auth link to initialise your client.

    ...
    final link = Link.from([freshLink, HttpLink('https://.../graphql/')]); 
    ...
    Client(
      link: _CustomAuthLink().concat(link),
    )
    ...
    
  3. 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.

Share:
421
B0r1
Author by

B0r1

Updated on December 01, 2022

Comments

  • B0r1
    B0r1 over 1 year

    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!

    • Aristidios
      Aristidios almost 2 years
      did you end up using fresh_graphql ? Documentation is quite minimal
    • B0r1
      B0r1 almost 2 years
      Yeah you can check the bloc discord group :)
    • Aristidios
      Aristidios almost 2 years
      Did you share your implementation on Discord ? Would you mind sharing a link ? : )