Implementing Auth in Flutter using Supabase and Getx
Tags: flutter, supabase, auth, get
Published: 2021-07-26 07:15:54

## Hey there!!!

Have you ever needed a backend service like *Firebase* for your Flutter app or website but didn't want to go through all the complex setup procedures of *Firebase*? Or have you felt like using a different backend service just because you're bored of using *Firebase* 😂?

Well , here comes the hero. Superman to the rescue!!!!

Oh wait , it's not Superman 😬, it's ***Supabase***.

### What is *Supabase*?
 
*Supabase* is an open-source backend-as-a-service developed as an alternative to *Firebase*. It is built using many other open-source packages and tools and it offers a lot of features that a developer needs for his app or web application. It has a relational database (PostgreSQL database) , built-in authentication and authorization , storage , real-time subscriptions, and much more!

>A relational database is one that stores data which have some relationships between them

Supabase is currently in public beta , and there are more features and functions to come when it goes public or when it is production-ready. Supabase has one of the best documentation out there. Check out their website.

https://supabase.io/

### What we're going to do

We'll create a flutter app and set up authentication in it using Supabase.
In this app, we'll also be using *Get*.
>**Get** is a package used for state management , route management, and dependency injection in flutter. It's quite easy to understand and get started with it.

>**State management** - Apps and websites have something called *state*. Whenever a user interacts with the app , the *state* of the app changes(in simple words , the app reacts to the user's action) . This *state* needs to be managed to define how and when it should change. This is done using the state management technique. Flutter comes with a built-in state management technique - *setstate*.

>**Route management** - Sometimes we may need to show different screens to the user , this is done using route management.

>**Dependency Injection** - Some objects in the app depend on another for its functioning , this is called dependency. To give the object what it needs is *dependency injection*(It's like passing a service to a client). With this , the object can be accessed anywhere in the widget tree easily.

https://pub.dev/packages/get

### Getting Started

Step 1. Create a flutter app.   
Step 2. Go to  [Supabase](https://supabase.io/) and click on *Start Project*.

![Screenshot (357).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627190988168/OK4WgMim9.png)
Step 3. If you are new to Supabase , it'll take you to the sign-in page. (If you already have signed in , skip to Step 6).   
Step 4. Click on *Continue with Github*.

![Screenshot (358).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627191004899/rqgPtKJbD.png)
Step 5. Enter your credentials and click on *Sign In*.

![Screenshot (359).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627191015122/hqJrh-0WX.png)
Step 6. Click on *New Project*.
![Screenshot (361).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627191065090/PPy9guva9.png)
Step 7. Give the project some name(I'll be naming it Auth) and type in a strong password(now , remember to remember the password), and then select the closest server region to your location.

![Screenshot (362).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627191191464/gWuAL8_qv.png)
Step 8. Just sit back and enjoy a cup of coffee while Supabase creates your project for you.
>Meanwhile you can check out their documentation and API references on their website.

![Screenshot (363).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627191295489/qnp7mKGm1.png)
Step 9. Once it is ready , go to *settings* and then *API* section.

![oie_HGC1zqysxFFI.jpg](https://cdn.hashnode.com/res/hashnode/image/upload/v1627191762315/lEwwTlZnE.jpeg)
Step 10. Note down your *project URL* and *project API key* , we will be needing them in our app. That's all we need to set up a backend service for our app.No other procedures involving the editing of *build.gradle* files etc like Firebase.

>Now go the *Authentication* section and then into *settings* and disable email confirmations or else we'll have to verify each email before it we sign In.

![Screenshot (372).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627269469698/lUxB9Fn-a.png)

Step 11. Go to the *table editor* section and click on *Create a new table*.

![Screenshot (364).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627194413655/LilApy0k3.png)

Step 12. Let's name it **Users** and leave the rest to default and click on *Save*.
We will be using this table to store the user data of registered users.

![Screenshot (367).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627194575587/L0vxgU9IH.png)

Step 13. Now click on the "+" icon beside the id column to create a new column.

![Screenshot (369).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627195278849/9Ep5nb7QO.png)
>We'll name it **Name** and set the type to **text** and unselect **Allow nullable** because we don't want the name of the user to be null by accident.

Step 14. We'll create 2 more columns **Email** and **Id** to store email and user Id.

![Screenshot (370).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627195571940/xaKdpH-eO.png)

![Screenshot (371).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627195579278/KxEtjQHVT.png)

That's it , now we have our database ready!!.

### Building the app

Let's open the app folder and go to *pubspec.yaml* and import the following packages :

https://pub.dev/packages/supabase
https://pub.dev/packages/get_storage
https://pub.dev/packages/get
https://pub.dev/packages/form_field_validator

>**get_storage** - Now let's assume that a user logs in to the app and uses it for some time and then exits the app. The next time he opens the app , it shouldn't take him to the login page again, right?  So , we need to store a **session** string for the user so that the app takes him to the home page. This is done using this package.


Now , go to *main.dart* and paste the following code :
```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Wrapper(),
    );
  }
}

class Wrapper extends StatefulWidget {
  @override
  WrapperState createState() => WrapperState();
}

class WrapperState extends State<Wrapper> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CircularProgressIndicator(),
      ),
    );
  }
}
```
>The Wrapper class is used to listen to auth changes(whether the user is logged in or not) in the app and take him to the appropriate page. 

Create 2 global variables and assign them the values you copied earlier.
```dart
final String _supaBaseUrl = 'Project URL';
final String _supaBaseKey = 'Project API key';
```
Import these in *main.dart*
```dart
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:supabase/supabase.dart';
```
Now create a dependency in *void main*
```dart
void main() {
  Get.put<SupabaseClient>(SupabaseClient(_supaBaseUrl, _supaBaseKey));
  Get.put<GetStorage>(GetStorage());
  runApp(MyApp());
}
```
>We create a SupabaseClient dependency to access all the functions of **supabase**.
**Get.put()** takes in a dependency to inject as an argument. We specify the type of dependency using less than and greater than operators.

>SupabaseClient takes in 2 arguments - project URL and project API key.

>We will also create a dependency for storing the **session string** and the type will be **GetStorage**.

Now , let's create a new file inside *lib* folder and name it *authService.dart*.
We will be implementing the authentication functions of our app in a separate class called *AuthService*.
Paste the following code in it :
```dart
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:supabase/supabase.dart';


class AuthService {
final _authClient=Get.find<SupabaseClient>();
//register user and create a custom user data in the database

//log in user

//get currently logged in user data

//logOut

//RecoverSession
  
}
```
>**Get.find()** finds the injected dependency instance in the whole widget tree and returns it. In our case, it is located in **main.dart**. We store it in a variable and use it later.

**Register user and create user data**
```dart
//register user and create a custom user data in the database
Future<GotrueSessionResponse> signUpUser(String name, String email, String password) async {
    final user =
        await _authClient.auth.signUp(email, password);
    final response =
        await _authClient.from('Users').insert([
      {"Id": user.user.id, "Name": name, "Email": email}
    ]).execute();
    if (response.error == null) {
      return user;
    }
  }
```
>We create a function **signUpUser()** which returns a Future of type **GotrueSessionResponse**.   
**Future** - Sometimes we need to retrieve data from the database or somewhere else where the data may not be readily available or may take some time to load depending upon your internet connection. Such data are called **Futures**.To use them in our code , we need to mark that part of code **async**(meaning asynchronous) and use the keyword **await** to await the data to arrive. When we use await in our code , whatever code comes after that **await** code line is executed only after the data arrives(or after the awaited code is completely executed).   

>To register the user , we use the **_authClient** variable and tap into  the **auth** property and then use the **signUp()** function.It takes 2 arguments - email and password.Since it return a Future of type **GotrueSessionResponse** , we use await.

>To create user data in our database, we use the **_authClient** variable and use the **from()** function which takes in the database name as an argument, and use the **insert** function which takes a list of Maps as an argument. Finally, we execute it.

>**Syntax : _authClient.from("Database name").insert([   
{"Column_1_name":value, "Column_2_name":value , and so on},      {"Column_1_name":value, "Column_2_name":value , and so on},   
and so on   
]).execute();**

**Log In User**

```dart
//log in user
  Future<GotrueSessionResponse> signIn(String email, String password) async {
    final user =
        await _authClient.auth.signIn(email: email, password: password);
    if (user.error == null) {
      return user;
    }
  }
```
>To log in the user , we use the **_authClient** variable and tap into  the **auth** property and then use the **signIn()** function.It takes 2 named arguments - email and password.Since it return a Future of type **GotrueSessionResponse** , we use await.

**Get current user**
```dart
//get currently logged in user data
User getCurrentUser() {
    return _authClient.auth.user();
  }
```
>The **user()** function returns user data of type **User** if there is a currently logged in user.

**Log out user**
```dart
//logOut
Future<GotrueResponse> logOut() async {
    await _authClient.auth.signOut();
  }
```
>The **signOut()** function simply signs out the current user(if there is a logged-in user) and returns a Future of type GotrueResponse. It takes no arguments.

**Recover user session**
```dart
//RecoverSession
  Future<GotrueSessionResponse> recoverSession(String session) async {
    return await _authClient.auth.recoverSession(session);
  }
```
>This function is to recover user session if a user has logged in , used the app for some time, and exited. It takes a String as an argument and returns a Future of type GotrueSessionResponse.

#### UI
Now it's time to add some makeup to our app and make it look beautiful.   
Go to *lib* folder and create a file called **loginPage.dart** and paste the following code : 
```dart
import 'package:supabase_auth/Screens/Auth/registerPage.dart';
import 'package:supabase_auth/Screens/Home/home.dart';
import 'package:supabase_auth/Services/authService.dart';
import 'package:flutter/material.dart';
import 'package:form_field_validator/form_field_validator.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';

class LoginPage extends StatefulWidget {
  String email = '';
  LoginPage({this.email});
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  AuthService _service = AuthService();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _formKey = GlobalKey<FormState>();
  bool logging = false, obscure = true;

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    _emailController.text = widget.email;
    return Scaffold(
      body: SingleChildScrollView(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Padding(
                padding: EdgeInsets.only(top: 100.0),
                child: Center(
                  child: Text(
                    'LOGIN',
                    style: TextStyle(
                      color: Colors.black,
                      fontSize: 50,
                    ),
                  ),
                ),
              ),
              Container(
                margin: EdgeInsets.only(
                  top: size.height / 6,
                  left: 40.0,
                  right: 40.0,
                ),
                decoration: BoxDecoration(
                  color: Colors.blue,
                  borderRadius: BorderRadius.circular(20.0),
                ),
                child: Padding(
                  padding: EdgeInsets.only(
                    top: 20.0,
                    left: 20.0,
                    right: 20.0,
                  ),
                  child: Form(
                    key: _formKey,
                    child: Column(
                      children: [
                        TextFormField(
                          controller: _emailController,
                          decoration: InputDecoration(
                            hintText: "Email",
                            hintStyle: TextStyle(color: Colors.white),
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                          ),
                          validator: MultiValidator([
                            RequiredValidator(errorText: "Required"),
                            EmailValidator(
                                errorText:
                                    "Please enter a valid email address"),
                          ]),
                        ),
                        SizedBox(
                          height: 20.0,
                        ),
                        TextFormField(
                          obscureText: true,
                          controller: _passwordController,
                          decoration: InputDecoration(
                            hintText: "Password",
                            hintStyle: TextStyle(color: Colors.white),
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                          ),
                          validator: MultiValidator([
                            RequiredValidator(errorText: "Required"),
                            MinLengthValidator(6,
                                errorText:
                                    "Password must contain atleast 6 characters"),
                            MaxLengthValidator(20,
                                errorText:
                                    "Password must not be more than 20 characters"),
                          ]),
                        ),
                        SizedBox(
                          height: 20.0,
                        ),
                        logging == false
                            ? ElevatedButton(
                                onPressed: () async {
                                  if (_formKey.currentState.validate()) {
                                    setState(() {
                                      logging = true;
                                    });
                                    login();
                                  }
                                },
                                child: Padding(
                                  padding:
                                      EdgeInsets.symmetric(horizontal: 50.0),
                                  child: Text(
                                    'Login',
                                    style: TextStyle(color: Colors.black),
                                  ),
                                ),
                                style: ButtonStyle(
                                  shape: MaterialStateProperty.all(
                                    RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(20.0),
                                    ),
                                  ),
                                  backgroundColor:
                                      MaterialStateProperty.all(Colors.white),
                                ),
                              )
                            : CircularProgressIndicator(
                                valueColor:
                                    AlwaysStoppedAnimation<Color>(Colors.black),
                              ),
                        SizedBox(
                          height: 20.0,
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            Text(
                              "Don't have an account? ",
                              style: TextStyle(color: Colors.white),
                            ),
                            InkWell(
                              onTap: () {
                                Navigator.pushReplacement(
                                  context,
                                  MaterialPageRoute(
                                    builder: (_) => RegisterPage(),
                                  ),
                                );
                              },
                              child: Text(
                                "Register",
                                style: TextStyle(
                                    color: Colors.black,
                                    fontWeight: FontWeight.bold),
                              ),
                            ),
                          ],
                        ),
                        SizedBox(height: 20.0),
                      ],
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future login() async {}
}

SnackBar snackBar({String content, String type}) => SnackBar(
      content: Text(
        content,
        style: TextStyle(
          color: Colors.white,
          fontSize: 20.0,
        ),
      ),
      backgroundColor: type == "Error" ? Colors.red : Colors.green,
    );
}

```
Go to the *lib* folder and create a file called **registerPage.dart** and paste the following code : 
```dart
import 'package:supabase_auth/Screens/Auth/loginPage.dart';
import 'package:supabase_auth/Services/authService.dart';
import 'package:flutter/material.dart';
import 'package:form_field_validator/form_field_validator.dart';

class RegisterPage extends StatefulWidget {
  @override
  _RegisterPageState createState() => _RegisterPageState();
}

class _RegisterPageState extends State<RegisterPage> {
  AuthService _service = AuthService();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _nameController = TextEditingController();
  final _formKey = GlobalKey<FormState>();
  bool registering = false;
  bool obscure = true;

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;

    return Scaffold(
      body: SingleChildScrollView(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Padding(
                padding: EdgeInsets.only(top: 100.0),
                child: Center(
                  child: Text(
                    'REGISTER',
                    style: TextStyle(
                      color: Colors.black,
                      fontSize: 50,
                    ),
                  ),
                ),
              ),
              Container(
                margin: EdgeInsets.only(
                  top: size.height / 6,
                  left: 40.0,
                  right: 40.0,
                ),
                decoration: BoxDecoration(
                  color: Colors.blue,
                  borderRadius: BorderRadius.circular(20.0),
                ),
                child: Padding(
                  padding: EdgeInsets.only(
                    top: 20.0,
                    left: 20.0,
                    right: 20.0,
                  ),
                  child: Form(
                    key: _formKey,
                    child: Column(
                      children: [
                        TextFormField(
                          controller: _nameController,
                          decoration: InputDecoration(
                            hintText: "Name",
                            hintStyle: TextStyle(color: Colors.white),
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                          ),
                          validator: MultiValidator([
                            RequiredValidator(errorText: "Required"),
                          ]),
                        ),
                        SizedBox(
                          height: 20.0,
                        ),
                        TextFormField(
                          controller: _emailController,
                          decoration: InputDecoration(
                            hintText: "Email",
                            hintStyle: TextStyle(color: Colors.white),
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                          ),
                          validator: MultiValidator([
                            RequiredValidator(errorText: "Required"),
                            EmailValidator(
                                errorText:
                                    "Please enter a valid email address"),
                          ]),
                        ),
                        SizedBox(
                          height: 20.0,
                        ),
                        TextFormField(
                          obscureText: true,
                          controller: _passwordController,
                          decoration: InputDecoration(
                            hintText: "Password",
                            hintStyle: TextStyle(color: Colors.white),
                            border: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                            focusedBorder: OutlineInputBorder(
                              borderRadius: BorderRadius.circular(20.0),
                            ),
                          ),
                          validator: MultiValidator([
                            RequiredValidator(errorText: "Required"),
                            MinLengthValidator(6,
                                errorText:
                                    "Password must contain atleast 6 characters"),
                            MaxLengthValidator(20,
                                errorText:
                                    "Password must not be more than 20 characters"),
                          ]),
                        ),
                        SizedBox(
                          height: 20.0,
                        ),
                        registering == false
                            ? ElevatedButton(
                                onPressed: () async {
                                  if (_formKey.currentState.validate()) {
                                    setState(() {
                                      registering = true;
                                    });
                                    register();
                                  }
                                },
                                child: Padding(
                                  padding:
                                      EdgeInsets.symmetric(horizontal: 50.0),
                                  child: Text(
                                    'Register',
                                    style: TextStyle(color: Colors.black),
                                  ),
                                ),
                                style: ButtonStyle(
                                  shape: MaterialStateProperty.all(
                                    RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(20.0),
                                    ),
                                  ),
                                  backgroundColor:
                                      MaterialStateProperty.all(Colors.white),
                                ),
                              )
                            : CircularProgressIndicator(
                                valueColor:
                                    AlwaysStoppedAnimation<Color>(Colors.black),
                              ),
                        SizedBox(
                          height: 20.0,
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            Text(
                              "Already have an account? ",
                              style: TextStyle(color: Colors.white),
                            ),
                            InkWell(
                              onTap: () {
                                Navigator.pushReplacement(
                                  context,
                                  MaterialPageRoute(
                                    builder: (_) => LoginPage(email: _emailController.text,),
                                  ),
                                );
                              },
                              child: Text(
                                "Login",
                                style: TextStyle(
                                    color: Colors.black,
                                    fontWeight: FontWeight.bold),
                              ),
                            ),
                          ],
                        ),
                        SizedBox(height: 20.0),
                      ],
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future register() async { }

  SnackBar snackBar({String content, String type}) => SnackBar(
        content: Text(
          content,
          style: TextStyle(
            color: Colors.white,
            fontSize: 20.0,
          ),
        ),
        backgroundColor: type == "Error" ? Colors.red : Colors.green,
      );
}

```
Next go to *main.dart* and inside *Wrapper* widget , paste the following
```dart
void sessionCheck() async {
    await GetStorage.init();
    final box = Get.find<GetStorage>();
    AuthService _authService = AuthService();
    final session = box.read('user');
    if (session == null) {
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(
          builder: (context) => LoginPage(),
        ),
      );
    } else {
      final response = await _authService.recoverSession(session);
      await box.write('user', response.data.persistSessionString);
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(
          builder: (context) => HomePage(),
        ),
      );
    }
  }
```
>We await *GetStorage()* to start/initialise the storage drive. Next, we find a GetStorage dependency instance and assign it to a variable called **box**.   
We then use this box variable and call a function **read()** which reads the storage drive/container and checks if there is a value associated with the key we pass as an argument to it. The value will be a **session string** and we store it in a variable named **session**. Why so? Because it makes sense😂.   
If there is no value present , then we take the user to the **LoginPage**.   
Else if there is some value present , we recover that session by calling the **recoverSession()** function we had defined in the **AuthService** class. We call that function using an instance of AuthService class.   
We store the returned value in a variable called **sessionResponse**.   


>Now we need to save this session again in the container so that we have access to it the next time the user opens the app.   
We do it by awaiting **box.write()** which takes 2 arguments :   
1.**key** = The name of the key where the value is stored. You can give it any name.   
2.**value** = The **session string** to be stored in the container and it will be associated with the key we specify.   
This function returns a Future of type void , so we await it. Once it is done , we go to the homePage.



Now that we have defined the function , we need to call it. Paste the following code in *main.dart* inside *Wrapper* widget
```dart
@override
  void initState() {
    // TODO: implement initState
    super.initState();
    sessionCheck();
  }
```
>**initState()** is a function that is automatically called when the widget in which it is(In this case it is Wrapper widget), is loaded onto the stack. Or in simple words, it is called when the Wrapper widget loads/fires in the app.

Now go back to *loginPage.dart* and go the **login** function in it.
>Suppose a user registers for the first time , we show him the LoginPage right?
So , after login , his **session string** has to be saved so that it is available to the app the next time he opens it. We add two lines to the login function :

```dart
Future login() async {
    final box = Get.find<GetStorage>();
    final result =
        await _service.signIn(_emailController.text, _passwordController.text);

    if (result.data != null) {
      await box.write('user', result.data.persistSessionString);
      ScaffoldMessenger.of(context).showSnackBar(
        snackBar(content: "Login successful", type: "Success"),
      );
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(
          builder: (context) => HomePage(),
        ),
      );
    } else if (result.error?.message != null) {
      ScaffoldMessenger.of(context).showSnackBar(
        snackBar(content: result.error.message, type: "Error"),
      );
    }
  }
```
Go to *registerPage.dart* and implement the register function
```dart
  Future register() async {
    final result = await _service.signUpUser(
        _nameController.text, _emailController.text, _passwordController.text);
    if (result.data != null) {
      setState(() {
        registering = false;
      });
      ScaffoldMessenger.of(context).showSnackBar(
        snackBar(content: "Registration Successful", type: "Success"),
      );
      Navigator.pushReplacement(
        context,
        MaterialPageRoute(
          builder: (context) => LoginPage(
            email: _emailController.text,
          ),
        ),
      );
    } else if (result.error.message != null) {
      setState(() {
        registering = false;
      });
      ScaffoldMessenger.of(context).showSnackBar(
        snackBar(content: result.error.message, type: "Error"),
      );
    }
  }
```

### Home Page
We'll create a file named *homePage.dart* inside *lib* folder. We'll just create a simple home page with just a single button to implement the logout function.
```dart
import 'package:supabase_auth/Services/authService.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  AuthService _authservice = AuthService();
  bool loading = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        title: Text("Home Page"),
        centerTitle: true,
      ),
      body: Center(
        child: loading == false
            ? ElevatedButton(
                onPressed: () async {
                  setState(() {
                    loading = true;
                  });
                  await logout();
                },
                child: Text("Log Out"),
              )
            : CircularProgressIndicator(),
      ),
    );
  }

  Future logout() async { }
}
```

### Log Out

```dart
Future logout() async {
    await _authservice.logOut();
    setState(() {
      loading = false;
    });
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(
        builder: (context) => LoginPage(),
      ),
    );
  }
```
>Just like earlier , we will use the **AuthService** class instance to call the **logOut()** function.    
Since it returns a Future , we await it and once it is done , we take the user to the **LoginPage**.

Now go to **authService.dart** and go to the **logOut** function.
```dart
//logOut user
Future<GotrueResponse> logOut() async {
    Get.find<GetStorage>().remove('user');
    await _authClient.auth.signOut();
  }
```
>Here we are removing the **session string** associated with the user because it is no longer needed once the user logs out. The **remove()** function removes the data from the container by key. It takes the key as an argument and returns a Future of type void.
 
### Run the app
Hmmm , yeah that's it. Go ahead and run the app on your mobile or an emulator.
Once you log in , you can check the database and see that your login details will be in the database/table we created.

### Next Steps 
Check out the full source code at github.

{% github AdityaSubrahmanyaBhat/supabase_auth %}

That's all folks , Thank you🙏