skip to Main Content

hello I have a case where when the user token expires the user does not switch to the loginPage page, even though I have set it here.
how do i solve this problem thanks.

enter image description here

i set it on splashscreen if token is not null then go to main page and if token is null then go to login page.
but when the token expires it still remains on the main page

Future<void> toLogin() async {
    Timer(
      const Duration(seconds: 3),
      () async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        String? token = prefs.getString(Constant.token);
        Navigator.pushReplacementNamed(
          context,
          token != null ? AppRoute.mainRoute : AppRoute.loginRoute,
          arguments: token,
        );
      },
    );
  }

and function when user login

CustomButtonFilled(
                                  title: 'Login',
                                  onPressed: () async {
                                    final prefs =
                                        await SharedPreferences.getInstance();
                                    prefs.setString(Constant.token, '');
                                    if (nimController.text.isEmpty ||
                                        passwordController.text.isEmpty) {
                                      showError('NIM/Password harus diisi');
                                    } else {
                                      setState(() {
                                        isLoading = true;
                                      });
                                      User? user = await userProvider.login(
                                          nimController.text,
                                          passwordController.text);
                                      setState(() {
                                        isLoading = false;
                                      });
                                      if (user == null) {
                                        showError('NIM/Password tidak sesuai!');
                                      } else {
                                        userProvider.user = user;
                                        Navigator.pushNamedAndRemoveUntil(
                                          context,
                                          '/main',
                                          (route) => false,
                                        );
                                      }
                                    }
                                  },
                                ),

and this call api

Future<User?> login(String nim, String password) async {
    String url = Constant.baseURL;
    try {
      var body = {
        'username': nim,
        'password': password,
      };
      var response = await http.post(
        Uri.parse(
          '$url/login_mhs',
        ),
        body: body,
      );
      if (response.statusCode == 200) {
        final token = jsonDecode(response.body)['data']['access_token'];
        //Ini mulai nyimpen token
        await UtilSharedPreferences.setToken(token);
        print(token);
        // print(await UtilSharedPreferences.getToken());
        return User.fromJson(jsonDecode(response.body));
      } else {
        return null;
      }
    } catch (e) {
      print(e);
      throw Exception();
    }
  }

2

Answers


  1. If your session expire feature has some predefine interval or logic than you have to implement it in splash screen and based on that you can navigate user further. Otherwise you want to handle it in API response only you have add condition for statusCode 401.

    checkSessionExpire(BuildContext context)
       if (response.statusCode == 200) { 
          //SuccessWork
       } else if (response.statusCode == 401) {
          //SessionExpire
       } else {
          return null
       }
    }
    
    Login or Signup to reply.
  2. you can just make your own HTTP client using Dio and add Interceptor to automatically regenerate idToken if expired using the refreshToken given.

    Http client gives an error if the refreshToken also gets expired.

    In that case, just navigate to the login screen.

    Full code for adding interceptor and making own HTTP client is given below

    import 'package:dio/dio.dart';
    
    import '../utils/shared_preference.dart';
    
    class Api {
      static Dio? _client;
      static Dio clientInstance() {
        if (_client == null) {
          _client = Dio();
          _client!.interceptors
              .add(InterceptorsWrapper(onRequest: (options, handler) async {
            if (!options.path.contains('http')) {
              options.path = 'your-server' + options.path;
            }
            options.headers['Authorization'] =
                'Bearer ${PreferenceUtils.getString('IdToken')}';
            return handler.next(options);
          }, onError: (DioError error, handler) async {
            if ((error.response?.statusCode == 401 &&
                error.response?.data['message'] == "Invalid JWT")) {
              if (PreferenceUtils.exists('refreshToken')) {
                await _refreshToken();
                return handler.resolve(await _retry(error.requestOptions));
              }
            }
            return handler.next(error);
          }));
        }
        return _client!;
      }
    
      static Future<void> _refreshToken() async {
        final refreshToken = PreferenceUtils.getString('refreshToken');
        final response = await _client!
            .post('/auth/refresh', data: {'refreshToken': refreshToken});
    
        if (response.statusCode == 201) {
          // successfully got the new access token
          PreferenceUtils.setString('accessToken', response.data);
        } else {
          // refresh token is wrong so log out user.
          PreferenceUtils.deleteAll();
        }
      }
    
      static Future<Response<dynamic>> _retry(RequestOptions requestOptions) async {
        final options = Options(
          method: requestOptions.method,
          headers: requestOptions.headers,
        );
        return _client!.request<dynamic>(requestOptions.path,
            data: requestOptions.data,
            queryParameters: requestOptions.queryParameters,
            options: options);
      }
    }
    

    Dio client = Api.clientInstance();
    var resposne = (hit any request);
       if(error in response is 401){
      //it is sure that 401 is because of expired refresh token as we 
      //already handled idTokoen expiry case in 401 error while 
      //adding interceptor.
    navigate to login screen for logging in again.
    }
    

    Please accept the solution if it solves your problem.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search