Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: remove redundant remove tokens #61

Merged
merged 2 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.6.1] - 2024-07-12

### Changes

- Removed redundant calls to `removeToken`

## [0.6.0] - 2024-06-05

### Changes
Expand Down
7 changes: 0 additions & 7 deletions lib/src/dio-interceptor-wrapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,6 @@ class SuperTokensInterceptorWrapper extends Interceptor {
type: DioExceptionType.unknown,
error: e),
);
} finally {
LocalSessionState localSessionState =
await SuperTokensUtils.getLocalSessionState();
if (localSessionState.status == LocalSessionStateStatus.NOT_EXISTS) {
await AntiCSRF.removeToken();
await FrontToken.removeToken();
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions lib/src/front-token.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:mutex/mutex.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:supertokens_flutter/src/utilities.dart';
import 'package:supertokens_flutter/supertokens.dart';
import 'package:supertokens_flutter/src/anti-csrf.dart';

class FrontToken {
static String? tokenInMemory;
Expand Down Expand Up @@ -148,6 +149,7 @@ class FrontToken {
await _removeTokenFromStorage();
await Utils.setToken(TokenType.ACCESS, "");
await Utils.setToken(TokenType.REFRESH, "");
await AntiCSRF.removeToken()
if (_tokenInfoMutex.isLocked) {
_tokenInfoMutex.release();
}
Expand Down
201 changes: 87 additions & 114 deletions lib/src/supertokens-http-client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,107 +74,98 @@ class Client extends http.BaseClient {
return _innerClient.send(customRequest.request);
}

try {
while (true) {
await _refreshAPILock.acquireRead();
// http package does not allow retries with the same request object, so we clone the request when making the network call
http.BaseRequest copiedRequest;
LocalSessionState preRequestLocalSessionState;
http.StreamedResponse response;
try {
copiedRequest = SuperTokensUtils.copyRequest(customRequest.request);
copiedRequest =
await _removeAuthHeaderIfMatchesLocalToken(copiedRequest);
preRequestLocalSessionState =
await SuperTokensUtils.getLocalSessionState();
String? antiCSRFToken = await AntiCSRF.getToken(
preRequestLocalSessionState.lastAccessTokenUpdate);

if (antiCSRFToken != null) {
copiedRequest.headers[antiCSRFHeaderKey] = antiCSRFToken;
}

SuperTokensTokenTransferMethod tokenTransferMethod =
SuperTokens.config.tokenTransferMethod;
copiedRequest.headers["st-auth-mode"] =
tokenTransferMethod.getValue();

// Adding Authorization headers
copiedRequest =
await Utils.setAuthorizationHeaderIfRequired(copiedRequest);

// Add cookies to request headers
String? newCookiesToAdd = await Client.cookieStore
?.getCookieHeaderStringForRequest(copiedRequest.url);
String? existingCookieHeader =
copiedRequest.headers[HttpHeaders.cookieHeader];

// If the request already has a "cookie" header, combine it with persistent cookies
if (existingCookieHeader != null && existingCookieHeader != "") {
copiedRequest.headers[HttpHeaders.cookieHeader] =
_generateCookieHeader(existingCookieHeader, newCookiesToAdd);
} else {
copiedRequest.headers[HttpHeaders.cookieHeader] =
newCookiesToAdd ?? "";
}

// http package does not allow retries with the same request object, so we clone the request when making the network call
response = await _innerClient.send(copiedRequest);
await Utils.saveTokenFromHeaders(response);
String? frontTokenInHeaders = response.headers[frontTokenHeaderKey];
SuperTokensUtils.fireSessionUpdateEventsIfNecessary(
wasLoggedIn: preRequestLocalSessionState.status ==
LocalSessionStateStatus.EXISTS,
status: response.statusCode,
frontTokenFromResponse: frontTokenInHeaders,
);

// Save cookies from the response
String? setCookieFromResponse =
response.headers[HttpHeaders.setCookieHeader];
await Client.cookieStore?.saveFromSetCookieHeader(
copiedRequest.url, setCookieFromResponse);
} finally {
_refreshAPILock.release();
while (true) {
await _refreshAPILock.acquireRead();
// http package does not allow retries with the same request object, so we clone the request when making the network call
http.BaseRequest copiedRequest;
LocalSessionState preRequestLocalSessionState;
http.StreamedResponse response;
try {
copiedRequest = SuperTokensUtils.copyRequest(customRequest.request);
copiedRequest =
await _removeAuthHeaderIfMatchesLocalToken(copiedRequest);
preRequestLocalSessionState =
await SuperTokensUtils.getLocalSessionState();
String? antiCSRFToken = await AntiCSRF.getToken(
preRequestLocalSessionState.lastAccessTokenUpdate);

if (antiCSRFToken != null) {
copiedRequest.headers[antiCSRFHeaderKey] = antiCSRFToken;
}

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.
*/
if (customRequest.sessionRefreshAttempts >=
SuperTokens.config.maxRetryAttemptsForSessionRefresh) {
throw SuperTokensException(
"Received a 401 response from ${customRequest.request.url}. 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.");
}
customRequest.sessionRefreshAttempts++;

customRequest.request =
await _removeAuthHeaderIfMatchesLocalToken(copiedRequest);

UnauthorisedResponse shouldRetry =
await onUnauthorisedResponse(preRequestLocalSessionState);
if (shouldRetry.status == UnauthorisedStatus.RETRY) {
// Here we use the original request because it wont contain any of the modifications we make
return await _sendWithRetry(customRequest);
} else {
if (shouldRetry.exception != null) {
throw SuperTokensException(shouldRetry.exception!.message);
} else
return response;
}
SuperTokensTokenTransferMethod tokenTransferMethod =
SuperTokens.config.tokenTransferMethod;
copiedRequest.headers["st-auth-mode"] =
tokenTransferMethod.getValue();

// Adding Authorization headers
copiedRequest =
await Utils.setAuthorizationHeaderIfRequired(copiedRequest);

// Add cookies to request headers
String? newCookiesToAdd = await Client.cookieStore
?.getCookieHeaderStringForRequest(copiedRequest.url);
String? existingCookieHeader =
copiedRequest.headers[HttpHeaders.cookieHeader];

// If the request already has a "cookie" header, combine it with persistent cookies
if (existingCookieHeader != null && existingCookieHeader != "") {
copiedRequest.headers[HttpHeaders.cookieHeader] =
_generateCookieHeader(existingCookieHeader, newCookiesToAdd);
} else {
return response;
copiedRequest.headers[HttpHeaders.cookieHeader] =
newCookiesToAdd ?? "";
}

// http package does not allow retries with the same request object, so we clone the request when making the network call
response = await _innerClient.send(copiedRequest);
await Utils.saveTokenFromHeaders(response);
String? frontTokenInHeaders = response.headers[frontTokenHeaderKey];
SuperTokensUtils.fireSessionUpdateEventsIfNecessary(
wasLoggedIn: preRequestLocalSessionState.status ==
LocalSessionStateStatus.EXISTS,
status: response.statusCode,
frontTokenFromResponse: frontTokenInHeaders,
);

// Save cookies from the response
String? setCookieFromResponse =
response.headers[HttpHeaders.setCookieHeader];
await Client.cookieStore?.saveFromSetCookieHeader(
copiedRequest.url, setCookieFromResponse);
} finally {
_refreshAPILock.release();
}
} finally {
LocalSessionState localSessionState =
await SuperTokensUtils.getLocalSessionState();
if (localSessionState.status == LocalSessionStateStatus.NOT_EXISTS) {
await AntiCSRF.removeToken();
await FrontToken.removeToken();

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.
*/
if (customRequest.sessionRefreshAttempts >=
SuperTokens.config.maxRetryAttemptsForSessionRefresh) {
throw SuperTokensException(
"Received a 401 response from ${customRequest.request.url}. 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.");
}
customRequest.sessionRefreshAttempts++;

customRequest.request =
await _removeAuthHeaderIfMatchesLocalToken(copiedRequest);

UnauthorisedResponse shouldRetry =
await onUnauthorisedResponse(preRequestLocalSessionState);
if (shouldRetry.status == UnauthorisedStatus.RETRY) {
// Here we use the original request because it wont contain any of the modifications we make
return await _sendWithRetry(customRequest);
} else {
if (shouldRetry.exception != null) {
throw SuperTokensException(shouldRetry.exception!.message);
} else
return response;
}
} else {
return response;
}
}
}
Expand Down Expand Up @@ -302,28 +293,10 @@ class Client extends http.BaseClient {
status: UnauthorisedStatus.API_ERROR,
error: SuperTokensException("Some unknown error occured"));
} finally {
LocalSessionState localSessionState =
await SuperTokensUtils.getLocalSessionState();

if (localSessionState.status == LocalSessionStateStatus.NOT_EXISTS) {
await FrontToken.removeToken();
await AntiCSRF.removeToken();
}

_refreshAPILock.release();
}
}

static Future clearTokensIfRequired() async {
LocalSessionState preRequestLocalSessionState =
await SuperTokensUtils.getLocalSessionState();
if (preRequestLocalSessionState.status ==
LocalSessionStateStatus.NOT_EXISTS) {
await AntiCSRF.removeToken();
await FrontToken.removeToken();
}
}

static String _cookieMapToHeaderString(Map<String, dynamic> cookieMap) {
return cookieMap.keys.map((e) => "$e=${cookieMap[e]}").join(";");
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ class Version {
"2.0",
"3.0"
];
static String sdkVersion = "0.6.0";
static String sdkVersion = "0.6.1";
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: supertokens_flutter
description: SuperTokens SDK for Flutter apps
version: 0.6.0
version: 0.6.1
homepage: https://supertokens.com/
repository: https://github.com/supertokens/supertokens-flutter
issue_tracker: https://github.com/supertokens/supertokens-flutter/issues
Expand Down
Loading