Skip to content

Commit

Permalink
feat(refresh-token-interceptor): implement refresh token interceptor
Browse files Browse the repository at this point in the history
Signed-off-by: Taranjeet Singh <[email protected]>
  • Loading branch information
singhtaranjeet committed Aug 25, 2023
1 parent dedd2a7 commit 11b93e8
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 14 deletions.
1 change: 1 addition & 0 deletions lib/fa_flutter_api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export 'src/interceptors/network_interceptor.dart';
export 'src/api_options/api_options.dart';
export 'src/interceptors/cache_interceptor.dart';
export 'src/interceptors/cancel_token_interceptor.dart';
export 'src/interceptors/refresh_token_interceptor.dart';
36 changes: 33 additions & 3 deletions lib/src/api_service_impl.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:fa_flutter_api_client/src/api_options/api_options.dart';
import 'package:fa_flutter_api_client/fa_flutter_api_client.dart';
import 'package:fa_flutter_api_client/src/implementations/refresh_token_logging_interceptor_impl.dart';
import 'package:fa_flutter_api_client/src/utils/constants.dart';
import 'package:fa_flutter_core/fa_flutter_core.dart' hide ProgressCallback;
import 'package:http_parser/http_parser.dart';
import 'package:path/path.dart';

import 'base/api_service.dart';

class ApiServiceImpl implements ApiService {
ApiServiceImpl({
required this.baseUrl,
Expand All @@ -30,11 +29,20 @@ class ApiServiceImpl implements ApiService {
if (interceptors != null && interceptors!.isNotEmpty) {
_dioFile!.interceptors.addAll(interceptors!);
}

_refreshTokenDio = Dio();
if (interceptors != null && interceptors!.isNotEmpty && isDebug) {
_refreshTokenDio!.interceptors.add(
RefreshTokenLoggingInterceptorImpl(),
);
}
}

String baseUrl;
Dio? _dio;

Dio? _refreshTokenDio;

Dio? _dioFile;

final List<Interceptor>? interceptors;
Expand All @@ -59,7 +67,20 @@ class ApiServiceImpl implements ApiService {
String? url,
String? body,
ApiOptions? options,
bool isRefreshTokenRequest = false,
}) async {
if (isRefreshTokenRequest) {
return _refreshTokenDio!.post<T>(
url ?? '$baseUrl$endpoint',
data: body,
options: Options(
headers: _formatHeaders(options),
receiveTimeout: options?.receiveTimeout,
sendTimeout: options?.sendTimeout,
),
);
}

return _dio!.post<T>(url ?? '$baseUrl$endpoint',
data: body,
options: Options(
Expand Down Expand Up @@ -153,6 +174,15 @@ class ApiServiceImpl implements ApiService {
return _dio;
}

@override
Dio getRefreshTokenApiClient() {
if (_refreshTokenDio == null) {
_refreshTokenDio = Dio();
}

return _refreshTokenDio!;
}

@override
String getIsAuthRequiredKey() => Constants.isAuthRequiredAPIKey;

Expand Down
3 changes: 3 additions & 0 deletions lib/src/base/api_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ abstract class ApiService {
String? endpoint,
String? body,
ApiOptions? options,
bool isRefreshTokenRequest = false,
});

Future<Response<T>> put<T>({
Expand Down Expand Up @@ -47,6 +48,8 @@ abstract class ApiService {

Dio? getApiClient();

Dio? getRefreshTokenApiClient();

/// get key for disabling auth for some requests.
String getIsAuthRequiredKey();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'dart:developer';

import 'package:fa_flutter_api_client/fa_flutter_api_client.dart';

/// This is only for refresh token logging
/// Do not use it for other purposes
class RefreshTokenLoggingInterceptorImpl extends LoggingInterceptor {
@override
void logPrint(String msg) {
log(msg);
}
}
22 changes: 11 additions & 11 deletions lib/src/interceptors/error_interceptor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ abstract class ErrorInterceptor extends Interceptor {
// () {
// },
// );
if (!isLoginApi) {
handleUnauthenticatedUser(unauthenticatedError);
}
return handler.reject(
UnauthenticatedError(
requestOptions: error.requestOptions,
response: error.response,
type: error.type,
error: error.error,
),
);
if (!isLoginApi) {
await handleUnauthenticatedUser(unauthenticatedError);
}
return handler.reject(
UnauthenticatedError(
requestOptions: error.requestOptions,
response: error.response,
type: error.error,
error: error.error,
),
);
// return null;
} else if (code == 403) {
return handler.reject(
Expand Down
29 changes: 29 additions & 0 deletions lib/src/interceptors/refresh_token_interceptor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import 'dart:async';

import 'package:dio/dio.dart';

abstract class RefreshTokenInterceptor extends QueuedInterceptorsWrapper {
bool isRefreshingSession = false;

@override
FutureOr<void> onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
try {
var updatedOptions = options;
if (isExpired(options)) {
updatedOptions = await refreshToken(options);
}
return handler.next(updatedOptions);
} catch (e) {
handler.next(options);
}
}

/// It will be called when [isExpired] is true
/// Return the updated [RequestOptions] with new token
FutureOr<RequestOptions> refreshToken(RequestOptions options);

bool isExpired(RequestOptions options);
}

0 comments on commit 11b93e8

Please sign in to comment.