getToken method

Future<String?> getToken(
  1. [bool forceRefresh = false]
)

Retrieves the current App Trust token.

Implementation

Future<String?> getToken([bool forceRefresh = false]) async {
  if (!kIsWeb) {
    return null;
  }

  final configuredToken = app.options.appTrustToken;
  if (!forceRefresh &&
      configuredToken != null &&
      configuredToken.isNotEmpty) {
    return configuredToken;
  }

  final state = _state;
  if (state == null) {
    throw _appTrustError(
      'not-activated',
      'Call FusabaseAppTrust.instance.activate() before getToken().',
    );
  }

  if (state.cachedToken == null) {
    await _loadPersistedToken(state);
  }

  final now = DateTime.now().millisecondsSinceEpoch;
  if (state.cachedToken != null &&
      state.cachedToken!.expireTimeMillis <=
          now + const Duration(seconds: 5).inMilliseconds) {
    state.cachedToken = null;
    app.setInternalAppTrustToken(null);
    app.setInternalPersistedAppTrustToken(null);
  }

  if (!forceRefresh &&
      state.cachedToken != null &&
      state.cachedToken!.expireTimeMillis >
          now + const Duration(seconds: 5).inMilliseconds) {
    return state.cachedToken!.token;
  }
  if (!forceRefresh && state.inFlight != null) {
    return (await state.inFlight!).token;
  }
  if (forceRefresh && state.inFlight != null) {
    try {
      await state.inFlight;
    } catch (_) {
      // Ignore the previous attempt and continue with a forced refresh.
    }
  }

  final provider = state.webProvider;
  if (provider == null) {
    throw _appTrustError(
      'missing-provider',
      'A web App Trust provider is required for web token retrieval.',
    );
  }

  state.inFlight =
      (() async {
        const action = 'attest';
        final attestationToken = await provider.getAttestationToken(action);
        final attestRequest = <String, dynamic>{
          'provider': _providerKeyForWeb('web', app.options.appID),
          'attestationToken': attestationToken,
          'action': action,
          'deviceInfo': {
            'platform': app.options.appType.toLowerCase(),
            'userAgent': attestation.getUserAgent(),
          },
        };
        final siteKey = _siteKeyForAttestationRequest(provider);
        if (siteKey != null && siteKey.isNotEmpty) {
          attestRequest['siteKey'] = siteKey;
        }
        final client = createClient(app);
        try {
          final response = await client.post(
            Uri.parse(_buildAttestUrl(app)),
            headers: {'content-type': 'application/json'},
            body: jsonEncode(attestRequest),
          );

          if (response.statusCode < 200 || response.statusCode > 299) {
            throw _appTrustError(
              'attestation-exchange-failed',
              'Attestation exchange failed (${response.statusCode}).',
            );
          }

          final json = jsonDecode(response.body);
          final token = json['attestToken'];
          if (token is! String || token.isEmpty) {
            throw _appTrustError(
              'invalid-attestation-response',
              'Attestation response missing attestToken.',
            );
          }

          final result = _AppTrustTokenResult(
            token: token,
            expireTimeMillis: _defaultExpiryMillis(),
          );
          state.cachedToken = result;
          app.setInternalAppTrustToken(result.token);
          app.setInternalPersistedAppTrustToken(result.token);
          _tokenController.add(result.token);
          await apptrustdb.setPersistedToken(_storageKey(app), {
            'token': result.token,
            'expireTimeMillis': result.expireTimeMillis,
            'updatedAtMillis': DateTime.now().millisecondsSinceEpoch,
          });
          return result;
        } finally {
          client.close();
          state.inFlight = null;
        }
      })();

  return (await state.inFlight!).token;
}