Fast Passwordless Auth in Flutter: Add a One-line Sign Up and Login with Device using Cotter
Tags: showdev, tutorial, flutter, passwords
Published: 2020-06-18 17:32:27

---
title: Fast Passwordless Auth in Flutter: Add a One-line Sign Up and Login with Device using Cotter
published: true
description: In this tutorial, we'll create a Flutter app from scratch that allows users to sign in with their device instead of using passwords or magic links.
date: 2020-06-16 17:00:00 UTC
tags: showdev, tutorial, flutter, passwords
canonical_url: https://blog.cotter.app/fast-passwordless-auth-in-flutter-add-a-one-line-sign-up-and-login-with-device-using-cotter/
cover_image: https://blog.cotter.app/content/images/2020/06/FlutterPasswordlessLogin-2.png
series: Passwordless Login for Flutter
---

If you're building an app, starting with the increasingly popular passwordless login is the way forward – it's secure, easy, and frictionless for the user.

In this tutorial, we'll create a Flutter app from scratch that allows users to **sign in with their device**.

### How it works.

When a user first signs up, we'll automatically trust the current device. This means that the user can **automatically log in when accessing your app from this device**. When the user wants to access the app from another device, the user can **simply tap a prompt in your app to approve** the login request.

# 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:

```
flutter create flutter_passwordless
cd flutter_passwordless
```

Run your new app:

```
flutter run
```


## Make a Login Page

We'll edit `lib/main.dart` to make our login 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️⃣ TOOD: Initialize Cotter
  // 2️⃣ TODO: Make Sign Up Function
  // 3️⃣ TODO: Make 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 Up button
            MaterialButton(
              onPressed: () {},
              color: Colors.deepPurpleAccent,
              textColor: Colors.white,
              child: Text("Sign Up"),
            ),
            // Login button
            OutlineButton(
              onPressed: () {},
              child: Text("Sign In With Device"),
              highlightedBorderColor: Colors.deepPurpleAccent,
              textColor: Colors.deepPurpleAccent,
            ),
          ],
        ),
      ),
    );
  }
}
```

We combined the Sign Up and Login page into one because they both only require the user's email to identify the user.

## Sign New Users Up

When a new user presses sign up, we'll register the user and set the current device as trusted to allow automatic logins from this device.

### Add Dependencies

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 Function
+  // 3️⃣ TODO: Make Login Function
  
   _showResponse(BuildContext context, String title, String content) {...}
  
   @override
   Widget build(BuildContext context) { ... }
 }
```
<!--kg-card-end: html-->

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

### Make a Sign Up Function

To sign up, call `cotter.signUpWithDevice` and input the user's email. This will create a new user in Cotter and trust the current device to allow logins.

```dart
  // 2️⃣ Make Sign Up Function
  void signUp(BuildContext context) async {
    try {
      // 🚀 One-line Sign Up
      var user = await cotter.signUpWithDevice(identifier: inputController.text);
      // This will create a new user in Cotter and trust the current device
          
      // 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>
### Make a Login Function

To sign in, call `cotter.signInWithDevice` . If the user is logging in from a device that they trust, they'll automatically be approved.

```dart
  // 3️⃣ Make Login Function
  void login(BuildContext context) async {
    try {
      // 🚀 One-line Login
      var event = await cotter.signInWithDevice(identifier: inputController.text, context: context);
      
      // Show the response
      _showResponse(context, event.approved ? "Login Success" : "Login Failed", "User id: ${event.userID}");
      print(event);
    } catch (e) {
      _showResponse(context, "Error", e.toString());
    }
  }
```
<figcaption>lib/main.dart</figcaption>

If the current device is not trusted, this will open a prompt asking the user to approve the request. [Check out how to log in from a non-trusted device in our documentation.](https://docs.cotter.app/sdk-reference/flutter/sign-in-with-device/authenticate-from-a-non-trusted-device)

### Call the Sign Up and Login Functions from our buttons

```diff
class HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
  		...
            // Sign Up button
            MaterialButton(
              onPressed: () {
+               signUp(context);
              },
              color: Colors.deepPurpleAccent,
              textColor: Colors.white,
              child: Text("Sign Up"),
            ),
            // Login button
            OutlineButton(
              onPressed: () {
+               login(context);
              },
              child: Text("Sign In With Device"),
              highlightedBorderColor: Colors.deepPurpleAccent,
              textColor: Colors.deepPurpleAccent,
            ),
  		...
  }
}
```
<figcaption>lib/main.dart</figcaption>
# That's it

You should be able to sign up and log in with an email address.

![Fast Passwordless Auth in Flutter using Cotter](https://dev-to-uploads.s3.amazonaws.com/i/8fjnsfaehpf1benxwaze.gif)

You can also check your terminal to see the returned [User](https://docs.cotter.app/api-reference/user-api/user-object) and [Event](https://docs.cotter.app/api-reference/event-object) objects from the signup and login functions.

# 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. [Approve login requests from a non-trusted device](https://docs.cotter.app/sdk-reference/flutter/sign-in-with-device/authenticate-from-a-non-trusted-device)
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/).