DEV Community

loading...
Cover image for Fast Passwordless Auth in Flutter: Add a One-line Sign Up and Login with Device using Cotter
Cotter

Fast Passwordless Auth in Flutter: Add a One-line Sign Up and Login with Device using Cotter

Putri Karunia
Co-founder of Cotter.app, web dev & design enthusiast.
Originally published at blog.cotter.app on ・5 min read

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

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.

dependencies:
  cotter:
pubspec.yaml

Check the latest releases in pub.dev. 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.

+ 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) { ... }
 }

You can create a free account at Cotter 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.

  // 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());
    }
  }
lib/main.dart

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.

  // 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());
    }
  }
lib/main.dart

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.

Call the Sign Up and Login Functions from our buttons

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,
            ),
        ...
  }
}
lib/main.dart

That's it

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

Fast Passwordless Auth in Flutter using Cotter

You can also check your terminal to see the returned User and Event 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
  2. Getting the Logged-in User
  3. Getting Access Token, ID Token, and Refresh Token

Questions & Feedback

If you have any questions or feedback, feel free to join Cotter's Slack Channel 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 and check out our documentation.

Discussion (1)

Collapse
jckodel_96 profile image
J.C.Ködel

I love how these companies think 100k users is "large". I have 440 NEW users every month and I'm not large. It would cost me more than US$ 500 per month to do what Firebase does for free.