Flutter Email & Phone Auth: 3 Simple Steps To Log Your Users In via Email, SMS, and WhatsApp using Cotter
Tags: showdev, tutorial, flutter, email
Published: 2020-06-24 21:46:02

---
title: Flutter Email & Phone Auth: 3 Simple Steps To Log Your Users In via Email, SMS, and WhatsApp using Cotter
published: true
date: 2020-06-23 17:00:00 UTC
tags: showdev, tutorial, flutter, email
canonical_url: https://blog.cotter.app/flutter-email-phone-auth-3-simple-steps-to-log-in-your-users-via-email-sms-and-whatsapp-using-cotter/
series: Passwordless Login for Flutter
---

 ![Flutter Email & Phone Auth: 3 Simple Steps To Log  Your Users In via Email, SMS, and WhatsApp using Cotter](https://blog.cotter.app/content/images/2020/06/FlutterEmailPhoneAuth-1.png)

When building an app, it's often a requirement to make sure your users are real and you want to know if they own the email or phone number that they signed up with so you can communicate via those channels.

In this tutorial, we'll build a flutter app that allows users to **sign up and sign in with their email or phone number**.

### In this post:

- [Create a Flutter App](#create-a-flutter-app)
- [Sign in with Email](#sign-in-with-email)
- [Sign in with Phone Number via SMS or WhatsApp](#sign-in-with-phone-number)
- [See the result: Sign in with Phone Number](#that-s-it)

# Create a Flutter App

If this is your first time making a Flutter app, check out their [installation guide.](https://flutter.dev/docs/get-started/install) To create a new flutter app, run:

```bash
flutter create flutter_passwordless
cd flutter_passwordless

// Run your app
flutter run
```

# Sign in with Email

### Make a Welcome Page

We'll edit `lib/main.dart` to make our welcome page. Replace the contents with the following code:

```dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Cotter Passwordless App',
      theme: ThemeData(
        primaryColor: Colors.deepPurpleAccent,
        buttonTheme: ButtonThemeData(minWidth: double.infinity),
      ),
      home: HomePage(),
    );
  }
}

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

// Our Home Page
class HomePageState extends State<HomePage> {
  final inputController = TextEditingController();

  // 1️⃣ TODO: Initialize Cotter
  // 2️⃣ TODO: Make Sign Up & Login Function

  // This is a helper function that shows the response
  // from our Sign Up and Login functions.
  _showResponse(BuildContext context, String title, String content) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(title),
        content: Text(content),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        padding: EdgeInsets.all(20),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Welcome Titles
            Text("🦊", style: TextStyle(fontSize: 50)),
            Text("Welcome.",
                style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30)),

            // Email Input Form
            Form(
              child: TextField(
                decoration: InputDecoration(labelText: "Email"),
                controller: inputController,
              ),
            ),

            // Sign In Button
            MaterialButton(
              onPressed: () {},
              color: Colors.deepPurpleAccent,
              textColor: Colors.white,
              child: Text("Sign In With Email"),
            ),
          ],
        ),
      ),
    );
  }
}
```

## Sign Up New Users or Login Existing Users

Notice that we only have a "Sign in" button. We've combined the sign up and login functionality. After verifying the user's email:

- **If it's a new user**, the SDK will automatically create a new user in Cotter, and return the new user to you.
- **If it's a user that already exists** in Cotter, the SDK will return the existing user information.

### Step 1: Add Cotter to your project

Add Cotter to your `pubspec.yaml`, then run `flutter pub get`.

```yaml
dependencies:
  cotter:
```
<figcaption>pubspec.yaml</figcaption>

Check the latest releases in [pub.dev](https://pub.dev/packages/cotter#-installing-tab-).

> You may need to restart your flutter for it to run pod install (stop `flutter run` and re-run it).

### Initialize Cotter

Import Cotter in your `lib/main.dart`, then initialize it inside `HomePageState`.

<!--kg-card-begin: html-->
```diff
+ import 'package:cotter/cotter.dart'; // Import Cotter

class HomePageState extends State {
  ...

  // 1️⃣ Initialize Cotter
+  Cotter cotter = new Cotter(apiKeyID: API_KEY_ID); // 👈 Specify your API KEY ID here

  // 2️⃣ TODO: Make Sign Up & Login Function
  
  _showResponse(BuildContext context, String title, String content) {...}
  
  @override
  Widget build(BuildContext context) { ... }
}
```
<figcaption>lib/main.dart</figcaption><!--kg-card-end: html-->

You can [create a free account at Cotter](https://dev.cotter.app) to get your `API_KEY_ID`.

### Step 2: Setup Deep-Linking

To sign in using email verification, we will open a secure in-app browser where the user can enter the OTP sent to their email. We'll need to set a redirect URL that points to your app to tell the in-app browser what to do after it's finished authenticating. Let's set the redirect URL as `myexample://auth_callback`.

**Setup in iOS**

Add the following to your `ios/Runner/Info.plist`.
<div></div>
<figcaption></figcaption>

```xml
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleTypeRole</key>
    <string>Editor</string>
    <key>CFBundleURLName</key>
    <string>myexample</string> <!-- 👈 Setting scheme to myexample:// -->
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myexample</string> <!-- 👈 Setting scheme to myexample://  -->
    </array>
  </dict>
</array>
```
<figcaption>ios/Runner/Info.plist</figcaption>

**Setup in Android**

Add the following to your `android/app/src/main/AndroidManifest.xml`.

```xml
<manifest ...>
    <application ...> 
    ...

    <!-- Add the lines from here -->
    <activity android:name=".CallbackActivity" >
      <intent-filter android:label="flutter_web_auth">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- 👇 This is for myexample://auth_callback -->
        <data android:scheme="myexample" android:host="auth_callback"/>
      </intent-filter>
    </activity>
    <!-- Until here -->

  </application>
</manifest>
```
<figcaption>android/app/src/main/AndroidManifest.xml</figcaption>

> Now stop `flutter run` and re-run it.

### Step 3: Make a Sign Up/Login Function

To sign in using email verification, call `cotter.signInWithEmailOTP`.

```dart
// 2️⃣ Make Sign Up & Login Function
  void signUpOrLogin(BuildContext context) async {
    try {
      // 🚀 Verify email, then create new user or login
      var user = await cotter.signInWithEmailOTP(
        redirectURL: "myexample://auth_callback",
        email: inputController.text,
      );

      // Show the response
      _showResponse(context, "User Created",
          "id: ${user.id}\nidentifier: ${user.identifier}");
      print(user);
    } catch (e) {
      _showResponse(context, "Error", e.toString());
    }
  }
```
<figcaption>lib/main.dart</figcaption>
### Call the function from our button

```diff
class HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
		  ...
              // Sign In Button
              MaterialButton(
                onPressed: () {
+                 signUpOrLogin(context);
                },
                color: Colors.deepPurpleAccent,
                textColor: Colors.white,
                child: Text("Sign in With Email"),
              ),
          ...
  }
}

```
<figcaption>lib/main.dart</figcaption>

## That's It for Email Login

Now you should be able to sign up and log in with email.

![Login with Email using Cotter's Flutter SDK](https://dev-to-uploads.s3.amazonaws.com/i/ysxxsee8rna711ikh5qg.gif)<figcaption>Log in with Email using Cotter's Flutter SDK</figcaption>

# Sign In with Phone Number

Let's add another page to try signing up with a phone number. Make a new file called `phoneSignIn.dart` inside the `lib` folder:

```bash
touch lib/phoneSignIn.dart
```

Then, copy the code below:

```dart
import 'package:flutter/material.dart';

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

class PhoneSignInPage extends StatefulWidget {
  @override
  PhoneSignInPageState createState() => PhoneSignInPageState();
}

// Our Home Page
class PhoneSignInPageState extends State<PhoneSignInPage> {
  final inputController = TextEditingController();

  // 1️⃣ TODO: Initialize Cotter
  // 2️⃣ TODO: Make Sign Up & Login Function

  // This is a helper function that shows the response
  // from our Sign Up and Login functions.
  _showResponse(BuildContext context, String title, String content) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(title),
        content: Text(content),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        padding: EdgeInsets.all(20),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text("Sign in with Phone Number.",
                style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
            Text("Open pre-built phone input form.",
                style: TextStyle(color: Colors.grey)),

            // Button to open a pre-built phone input form
            Container(
              margin: EdgeInsets.symmetric(vertical: 30),
              child: MaterialButton(
                onPressed: () {},
                color: Colors.deepPurpleAccent,
                textColor: Colors.white,
                child: Text("Sign In with Phone"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

```
<figcaption>lib/phoneSignIn.dart</figcaption>
### Go to Phone Sign In Page from the Home Page

Let's make a button in our home page to go to this new `PhoneSignInPage`. Add a button in `lib/main.dart`.

<!--kg-card-begin: html-->
```dart
import 'package:flutter_passwordless/phoneSignIn.dart';

class HomePageState extends State {
  @override
  Widget build(BuildContext context) {
    ...
        // Sign In Button
        MaterialButton(
          onPressed: () { signUpOrLogin(context); },
          color: Colors.deepPurpleAccent,
          textColor: Colors.white,
          child: Text("Sign In With Email"),
        ),

        // Button to go to Phone sign in
        OutlineButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => PhoneSignInPage()),
            );
          },
          color: Colors.deepPurpleAccent,
          textColor: Colors.deepPurpleAccent,
          child: Text("Go to Phone Sign In \u2192"),
        ),  
    ...
  }
}

```
<figcaption>lib/main.dart</figcaption><!--kg-card-end: html-->
### Initialize Cotter

Just like before, import Cotter in your `lib/phoneSignIn.dart`, then initialize it inside `HomePageState`.

<!--kg-card-begin: html-->
```diff
+ import 'package:cotter/cotter.dart'; // Import Cotter

class PhoneSignInPageState extends State {
  ...

  // 1️⃣ Initialize Cotter
+  Cotter cotter = new Cotter(apiKeyID: API_KEY_ID); // 👈 Specify your API KEY ID here
  // 2️⃣ TODO: Make Sign Up & Login Function

  _showResponse(BuildContext context, String title, String content) {...}

  @override
  Widget build(BuildContext context) {...}
```
<figcaption>lib/phoneSignIn.dart</figcaption><!--kg-card-end: html-->

Open your [dashboard](https://dev.cotter.app/) to get your `API_KEY_ID`. To send SMS or WhatsApp messages, you need to add a balance to your account.

### Make a Sign Up/Login Function

To sign in using phone verification, call `cotter.signInWithPhoneOTP`. This will open a pre-built phone number input inside the in-app browser. [You can also use your own input form if you want.](https://docs.cotter.app/sdk-reference/flutter/sign-in-with-email-phone-number#step-4-logging-in)
```dart
  // 2️⃣ Make Sign Up & Login Function
  void signUpOrLogin(BuildContext context) async {
    try {
      // 🚀 Verify phone number, then create new user or login
      var user = await cotter.signInWithPhoneOTP(
        redirectURL: "myexample://auth_callback",
        channels: [PhoneChannel.SMS, PhoneChannel.WHATSAPP], // show SMS and WhatsApp options
      );

      // Show the response
      _showResponse(context, "Sign In Success",
          "User id: ${user.id}\nidentifier: ${user.identifier}");
      print(user);
    } catch (e) {
      _showResponse(context, "Error", e.toString());
    }
  }
```
<figcaption>lib/phoneSignIn.dart</figcaption>
### Call the function from our button

```diff
class PhoneSignInPageState extends State<PhoneSignInPage> {
  @override
  Widget build(BuildContext context) {
  		...
            // Button to open a pre-built phone input form
            Container(
              margin: EdgeInsets.symmetric(vertical: 30),
              child: MaterialButton(
                onPressed: () {
+                 signUpOrLogin(context);
                },
                color: Colors.deepPurpleAccent,
                textColor: Colors.white,
                child: Text("Sign In with Phone"),
              ),
            ),
        ...
  }
}
```
<figcaption>lib/phoneSignIn.dart</figcaption>

# That's It

Now you should be able to login using your phone number via SMS or WhatsApp.

![Phone Login via SMS or WhatsApp using Cotter's Flutter SDK](https://dev-to-uploads.s3.amazonaws.com/i/e0qcj5ykglap86lg6wqi.gif)<figcaption>Phone Login via SMS or WhatsApp using Cotter's Flutter SDK</figcaption>

# What's Next?

The `signUp` and `login` functions that you implemented automatically create access tokens for you and store it securely within the device. It also saves the currently logged-in user and automatically refreshes your access token when it's expired. Learn how to:

1. [Implement Sign in with Device](https://dev.to/cotter/fast-passwordless-auth-in-flutter-add-a-one-line-sign-up-and-login-with-device-using-cotter-29c0) so you don't have to send an email or SMS on every login.
2. [Getting the Logged-in User](https://docs.cotter.app/sdk-reference/flutter/sign-in-with-device/getting-the-logged-in-user)
3. [Getting Access Token, ID Token, and Refresh Token](https://docs.cotter.app/sdk-reference/flutter/sign-in-with-device/getting-oauth-tokens)

* * *

### Questions & Feedback

If you have any questions or feedback, feel free to join [Cotter's Slack Channel](https://join.slack.com/t/askcotter/shared_invite/zt-dxzf311g-5Mp3~odZNB2DwYaxIJ1dJA)and chat us there.  

### Ready to use Cotter?
If you enjoyed this tutorial and want to integrate Cotter into your website or app, you can [create a free account](https://dev.cotter.app/) and [check out our documentation](https://docs.cotter.app/).