Hello FlutterFlow community, I've been working on a custom interceptor to server as a JWT refresh mechanism. However, the documentation is VERY sparse and it took a lot of trial and error. I just thought I would share this here to possible help anyone else having difficulties with this.
Feel free to reach out with questions or suggestions for improvement!
This will be best applied to projects that are utilizing custom authentication with the built in Authenticated User.
Here is my working implementation:
// Automatic FlutterFlow imports
import '/backend/schema/structs/index.dart';
import '/backend/schema/enums/enums.dart';
import '/actions/actions.dart' as action_blocks;
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import 'index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
import 'dart:convert'; // For JSON encoding/decoding
import 'dart:developer'; // For logging
import '/backend/api_requests/api_interceptor.dart';
import '/auth/custom_auth/auth_util.dart'; // Import your auth manager
import '/backend/api_requests/api_calls.dart'; // Import the RefreshTokenCall
class ExpiryCheckInterceptor extends FFApiInterceptor {
@override
Future<ApiCallOptions> onRequest({
required ApiCallOptions options,
}) async {
log("Checking JWT token expiry now");
// Access the token expiration from your custom auth manager
final tokenExpiration = authManager.tokenExpiration; // Directly access it
final refreshToken = authManager.refreshToken; // Fetch refresh token
if (tokenExpiration != null && refreshToken != null) {
log("Got token expiration and refresh token");
final currentTime = DateTime.now();
final timeDifference = tokenExpiration.difference(currentTime);
// Check if the token needs refreshing
if (timeDifference.isNegative || timeDifference.inMinutes <= 10) {
log('Token is expired or will expire soon. Refreshing...');
try {
final response = await RefreshTokenCall.call(
refreshToken: refreshToken,
);
if (response.statusCode == 200) {
log('Token refreshed successfully.');
final responseBody = response.jsonBody;
// Update auth manager with new tokens
authManager.updateAuthUserData(
authenticationToken: responseBody['access_token'],
tokenExpiration: tokenExpiryTime(responseBody['expires_in']),
refreshToken: responseBody['refresh_token']);
// Update options with the new token
options.headers['Authorization'] =
'Bearer ${responseBody['access_token']}';
} else {
log('Failed to refresh token: ${response.statusCode}');
}
} catch (e) {
log('Error while refreshing token: $e');
}
} else {
log("Token is valid for more than 10 minutes");
}
} else {
log('No token expiration or refresh token found. User might not be authenticated.');
}
// Proceed with the original request
return options;
}
@override
Future<ApiCallResponse> onResponse({
required ApiCallResponse response,
required Future<ApiCallResponse> Function() retryFn,
}) async {
// Simply return the original response for now
return response;
}
}