How to redirect to a login page if Flutter API response is unauthorized?

1,712

Since you already have a MaterialApp in your tree and the named routes registered, this should be as simple as adding a call to push your login page around the same time you get the response.

First, you should modify getTables to check response for the status code with statusCode property of the Response object and shown with the following code block:

var response = await http.get('$_baseUrl/tables/list');

if(response.statusCode == 401) {
  //Act on status of 401 here
}

Now that you have a way of checking when the response has a status code of 401, you can navigate to your login page with the Navigator. The Navigator needs BuildContext, so that must be passed to the getTables function.

This involves modifying getTables to be:

Future<List<Tbl>> getTables(BuildContext context) async {

and fetchTables needs a similar change:

Future fetchTables(BuildContext context) async {

Then, where these methods are called, you pass context down:

In Tables

model.fetchTables(context)

In TablesModel

Future fetchTables(BuildContext context) async {
  setBusy(true);
  tables = await _api.getTables(context);
  setBusy(false);
}

and finally in getTables, you use the passed context to use the Navigator:

Future<List<Tbl>> getTables(BuildContext context) async {
  var tables = List<Tbl>();
  try {
      var response = await http.get('$_baseUrl/tables/list');

      //Check response status code
      if(response.statusCode == 401) {
        Navigator.of(context).pushNamed(RoutePaths.Login);//Navigator is used here to go to login only with 401 status code
        return null;
      }

      var parsed = json.decode(response.body) as List<dynamic>;

      if (parsed != null) {
         for (var table in parsed) {
             tables.add(Tbl.fromJson(table));
         }
      }

  } catch (e) {print(e); return null;}
  return tables;
}

Instead of Navigator.of(context).pushNamed(RoutePaths.Login);, you could use Navigator.pushNamed(context, RoutePaths.Login); if you prefer, but as you can read at this answer, they internally do the same thing.

Now when there is a status code of 401, a user will be navigated to the login screen.

Share:
1,712
markhorrocks
Author by

markhorrocks

Updated on December 23, 2022

Comments

  • markhorrocks
    markhorrocks over 1 year

    I am building a Flutter app which uses a Golang API to fetch data. The API will return a 401 unauthorized if the JWT token is not valid. How can I redirect to a login page on any API call if the response status is 401?

    Here is my flutter code:

    main.dart

    void main() async {
    
      WidgetsFlutterBinding.ensureInitialized();
    
      Provider.debugCheckInvalidValueType = null;
    
      AppLanguage appLanguage = AppLanguage();
      
      await appLanguage.fetchLocale();
      
      runApp(MyApp(
        appLanguage: appLanguage,
      ));
    
    }
    
    class MyApp extends StatelessWidget {
      
      final AppLanguage appLanguage;
    
      MyApp({this.appLanguage});
    
      @override
      Widget build(BuildContext context) {
    
        return  MultiProvider(
              
                      providers: providers,
    
                      child: MaterialApp(
                                
                          localizationsDelegates: [
                             AppLocalizations.delegate,
                             GlobalMaterialLocalizations.delegate,
                             GlobalWidgetsLocalizations.delegate,
                          ],
              
                      initialRoute: RoutePaths.Login,
                      onGenerateRoute: Router.generateRoute,
                      )        
                   );
            }  
    }
    

    tables.dart

    class Tables extends StatelessWidget {
    
      const Tables({Key key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
    
        return BaseWidget<TablesModel>(
        
            model: TablesModel(api: Provider.of(context, listen: false)),
        
            onModelReady: (model) => model.fetchTables(),
        
            builder: (context, model, child) => model.busy
    
                ? Center(
    
                    child: CircularProgressIndicator(),
                  
                  )
            
                : Expanded(
                   
                     child: GridView.builder (
    ---
    

    tables_model.dart

    class TablesModel extends BaseModel {
      
      Api _api;
    
      TablesModel({@required Api api}) : _api = api;
    
      List<Tbl> tables;
    
      Future fetchTables() async {
        setBusy(true);
        tables = await _api.getTables();
        setBusy(false);
      }
    
      @override
      void dispose() {
        print('Tables has been disposed!!');
        super.dispose();
      }
    }
    

    api.dart

    Future<List<Tbl>> getTables() async {
        
        var tables = List<Tbl>();
    
        try {
    
            var response = await http.get('$_baseUrl/tables/list');
    
            var parsed = json.decode(response.body) as List<dynamic>;
        
            if (parsed != null) {
    
               for (var table in parsed) {
        
                   tables.add(Tbl.fromJson(table));
        
               }
            }
    
        } catch (e) {print(e); return null;}
    
        return tables;
      }