refreshToken method

Future<AuthResult> refreshToken()

Refresh access token

Implementation

Future<AuthResult> refreshToken() async {
  try {
    // Get refresh token (try all sources)
    final refreshToken = await getRefreshTokenAsync();
    if (refreshToken == null || refreshToken.isEmpty) {
      _logger.debug('No refresh token available');
      return AuthResult.failure('No refresh token available');
    }

    // Get device ID (try all sources, matching getRefreshTokenAsync pattern)
    var deviceId = getDeviceId();
    if (deviceId == null || deviceId.isEmpty) {
      // Try cache
      deviceId = _secureCache['com.runanywhere.sdk.deviceId'];
    }
    if (deviceId == null || deviceId.isEmpty) {
      // Try secure storage directly
      try {
        const storage = FlutterSecureStorage(
          aOptions: AndroidOptions(encryptedSharedPreferences: true),
          iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
        );
        deviceId = await storage.read(key: 'com.runanywhere.sdk.deviceId');
        if (deviceId != null && deviceId.isNotEmpty) {
          _secureCache['com.runanywhere.sdk.deviceId'] = deviceId;
        }
      } catch (e) {
        _logger.debug('Failed to read device ID from secure storage: $e');
      }
    }
    if (deviceId == null || deviceId.isEmpty) {
      // Fallback: get from DartBridgeDevice
      deviceId = await DartBridgeDevice.instance.getDeviceId();
      if (deviceId.isNotEmpty) {
        _secureCache['com.runanywhere.sdk.deviceId'] = deviceId;
      }
    }
    if (deviceId == null || deviceId.isEmpty) {
      _logger.debug('No device ID available');
      return AuthResult.failure('No device ID available');
    }

    // Build refresh request JSON
    final requestJson = jsonEncode({
      'device_id': deviceId,
      'refresh_token': refreshToken,
    });

    _logger.debug('Refreshing token for device: $deviceId');

    // Make HTTP request
    final endpoint = _getRefreshEndpoint();
    final baseURL = _baseURL ?? _getDefaultBaseURL();
    final url = Uri.parse('$baseURL$endpoint');

    final headers = <String, String>{
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    };

    final response = await http.post(url, headers: headers, body: requestJson);

    if (response.statusCode == 200 || response.statusCode == 201) {
      final authData = _parseAuthResponse(response.body);

      // Try C++ handler first
      final cppSuccess = _handleRefreshResponse(response.body);

      // Also manually store tokens in secure storage (in case C++ handler unavailable)
      await _storeAuthTokens(authData);

      if (cppSuccess || authData.accessToken != null) {
        _logger.info('Token refresh successful');
        return AuthResult.success(authData);
      } else {
        return AuthResult.failure('Failed to parse refresh response');
      }
    } else {
      final errorMsg = _parseAPIError(response.body, response.statusCode);
      _logger.warning('Token refresh failed: $errorMsg');
      return AuthResult.failure(errorMsg);
    }
  } catch (e) {
    _logger.error('Token refresh error', metadata: {'error': e.toString()});
    return AuthResult.failure(e.toString());
  }
}