onResponse method

  1. @override
void onResponse(
  1. dynamic response,
  2. dynamic handler
)

Implementation

@override
void onResponse(Response response, ResponseInterceptorHandler handler) async {
  logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Intercepting response call');
  if (!shouldRunDioInterceptor(response.requestOptions)) {
    logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Skipping dio interceptor');
    return handler.next(response);
  }

  logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Running dio interceptor');
  _refreshAPILock.acquireWrite();
  logDebugMessage('SuperTokensInterceptorWrapper.onResponse: write acquired');
  logDebugMessage('SuperTokensInterceptorWrapper.onResponse: saving tokens from headers');
  await saveTokensFromHeaders(response);
  String? frontTokenFromResponse =
      response.headers.map[frontTokenHeaderKey]?.first.toString();
  logDebugMessage('SuperTokensInterceptorWrapper.onResponse: frontTokenFromResponse: ${frontTokenFromResponse}');
  SuperTokensUtils.fireSessionUpdateEventsIfNecessary(
    wasLoggedIn:
        _preRequestLocalSessionState.status == LocalSessionStateStatus.EXISTS,
    status: response.statusCode!,
    frontTokenFromResponse: frontTokenFromResponse,
  );
  List<dynamic>? setCookieFromResponse =
      response.headers.map[HttpHeaders.setCookieHeader];
  logDebugMessage('SuperTokensInterceptorWrapper.onResponse: setCookieFromResponse length: ${setCookieFromResponse?.length}');
  setCookieFromResponse?.forEach((element) async {
    await Client.cookieStore
        ?.saveFromSetCookieHeader(response.realUri, element);
  });

  try {
    if (response.statusCode == SuperTokens.sessionExpiryStatusCode) {
      /**
       * An API may return a 401 error response even with a valid session, causing a session refresh loop in the interceptor.
       * To prevent this infinite loop, we break out of the loop after retrying the original request a specified number of times.
       * The maximum number of retry attempts is defined by maxRetryAttemptsForSessionRefresh config variable.
       */
      logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Got expiry status code');
      RequestOptions requestOptions = response.requestOptions;
      int sessionRefreshAttempts =
          requestOptions.extra["__supertokensSessionRefreshAttempts"] ?? 0;
      if (sessionRefreshAttempts >=
          SuperTokens.config.maxRetryAttemptsForSessionRefresh) {
        logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Max attempts of ${SuperTokens.config.maxRetryAttemptsForSessionRefresh} reached for refreshing, cannot continue');
        handler.reject(
          DioException(
            requestOptions: response.requestOptions,
            type: DioExceptionType.unknown,
            error: SuperTokensException(
                "Received a 401 response from ${response.requestOptions.uri}. Attempted to refresh the session and retry the request with the updated session tokens ${SuperTokens.config.maxRetryAttemptsForSessionRefresh} times, but each attempt resulted in a 401 error. The maximum session refresh limit has been reached. Please investigate your API. To increase the session refresh attempts, update maxRetryAttemptsForSessionRefresh in the config."),
          ),
        );
        _refreshAPILock.release();
        return;
      }

      logDebugMessage('SuperTokensInterceptorWrapper.onResponse: removing auth header if it matches token');
      requestOptions =
          await _removeAuthHeaderIfMatchesLocalToken(requestOptions);
      UnauthorisedResponse shouldRetry =
          await Client.onUnauthorisedResponse(_preRequestLocalSessionState);
      if (shouldRetry.status == UnauthorisedStatus.RETRY) {
        logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Got RETRY status');
        logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Refreshing attempt: ${sessionRefreshAttempts + 1}');
        requestOptions.headers[HttpHeaders.cookieHeader] = userSetCookie;

        requestOptions.extra["__supertokensSessionRefreshAttempts"] =
            sessionRefreshAttempts + 1;

        Response<dynamic> res = await client.fetch(requestOptions);
        List<dynamic>? setCookieFromResponse =
            res.headers.map[HttpHeaders.setCookieHeader];
        logDebugMessage('SuperTokensInterceptorWrapper.onResponse: setCookieFromResponse length: ${setCookieFromResponse?.length}');
        setCookieFromResponse?.forEach((element) async {
          await Client.cookieStore
              ?.saveFromSetCookieHeader(res.realUri, element);
        });
        logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Saving tokens from headers');
        await saveTokensFromHeaders(res);
        logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Calling next on handler');
        return handler.next(res);
      } else {
        if (shouldRetry.exception != null) {
          logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Got non null exception');
          handler.reject(
            DioException(
                requestOptions: response.requestOptions,
                error: SuperTokensException(shouldRetry.exception!.message),
                type: DioExceptionType.unknown),
          );
          return;
        } else {
          _refreshAPILock.release();
          logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Calling next on handler');
          return handler.next(response);
        }
      }
    } else {
      _refreshAPILock.release();
      logDebugMessage('SuperTokensInterceptorWrapper.onResponse: Calling next on handler');
      return handler.next(response);
    }
  } on DioException catch (e) {
    handler.reject(e);
  } catch (e) {
    handler.reject(
      DioException(
          requestOptions: response.requestOptions,
          type: DioExceptionType.unknown,
          error: e),
    );
  }
}