Flutter apps With AWS Amplify Backend: Part 2 — Authentication

thatflutterdude

FlutterArticles

Posted on September 10, 2020

Flutter apps With AWS Amplify Backend: Part 2 — Authentication

Flutter apps With AWS Amplify Backend: Part 2 — Authentication

Setting up authentication in a Flutter application is easy with the help of AWS Cognito, now available through Amplify Flutter. If you haven’t check out Part 1 of this series, I suggest you do that first.

What are we making?

We will be making a simple registration and login system for a Flutter application that uses AWS Cognito as the authentication backend.

The login is very low latencyThe login is very low latency

As always, you can find the code for this tutorial at our Github repo.

What do we need?

The only thing you need for this tutorial is the app you created in Part 1 of this tutorial series, which is just a sample app with *amplify *initialized.

If you don’t want to read part 1 and you are already familiar with Amplify Flutter, then simply create a new Flutter application and connect it to a cloud instance of Amplify.

Let’s Get Started

Create a Basic Amplify Project

If you are using the app you created in Part 1, you can skip this step.

Otherwise, create a new flutter project, and from the project directory run:

amplify init
Enter fullscreen mode Exit fullscreen mode

Add AWS Cognito to our Project

From the integrated terminal, run

amplify add auth
Enter fullscreen mode Exit fullscreen mode

This adds AWS Cognito* *to your project. After following the setup wizard, your terminal should look something like this:

Note that we are going to be using emails as the authentication method. I will cover the other methods in future tutorials.

Next, follow the instructions given in the terminal and run amplify push to deploy authentication to your cloud project.y

Checking on the Status of our Resources

You can check the status of your cloud resources by running amplify status.

At this point, a user pool should have been created in the cloud for your AWS Cognito service. Go to your user pools (make sure you select your region) and you should see a new user pool.

Interacting with Cloud Resources

A few steps are needed to interact with the cloud, if you just want the final result and don’t care about the step-by-step, go here for a checkpoint commit.

Many of these code snippets are derived from the AWS documentation. I will give explanations about what each logical component does, and provide you with a working example of a login form.

  1. Add packages to pubspec.yaml

This gives us access to the dart packages for amplify.

amplify_core: '<1.0.0'
amplify_auth_cognito: '<1.0.0'
Enter fullscreen mode Exit fullscreen mode
  1. Amplify Initialization

This code snippet initializes our authentication plugin (and any other plugins we may have) and sets our apps flags so that we can handle an unsuccessful cloud connection in our app.

void _configureAmplify() async {
  if (!mounted) return;

  // add all of the plugins we are currently using
  // in our case... just one - Auth
  AmplifyAuthCognito authPlugin = AmplifyAuthCognito();
  amplifyInstance.addPlugin(authPlugins: [authPlugin]);

  await amplifyInstance.configure(amplifyconfig);
  try {
    setState(() {
      _amplifyConfigured = true;
    });
  } catch (e) {
    print(e);
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Register a User

Registering a user makes use of text controllers (not shown here). Once again, state flags (isSignUpComplete in this case) are set based on the result of the SignUp operation.

  Future<String> _registerUser(LoginData data) async
  {
    try {
      Map<String, dynamic> userAttributes = {
        "email": emailController.text,
      };
      SignUpResult res = await Amplify.Auth.signUp(
          username: data.name,
          password: data.password,
          options: CognitoSignUpOptions(
              userAttributes: userAttributes
          )
      );
      setState(() {
        isSignUpComplete = res.isSignUpComplete;
        print("Sign up: " + (isSignUpComplete ? "Complete" : "Not Complete"));
      });
    } on AuthError catch (e) {
      print(e);
      return "Register Error: " + e.toString();
    }
  }
Enter fullscreen mode Exit fullscreen mode

4. Sign In a User

  Future<String> _signIn(LoginData data) async {
    try {
      SignInResult res = await Amplify.Auth.signIn(
        username: data.name,
        password: data.password,
      );
      setState(() {
        isSignedIn = res.isSignedIn;
      });

      if (isSignedIn)
        Alert(context: context, type: AlertType.success, title: "Login Success").show();

    } on AuthError catch (e) {
      print(e);
      Alert(context: context, type: AlertType.error, title: "Login Failed").show();
      return 'Log In Error: ' + e.toString();
    }
  }
Enter fullscreen mode Exit fullscreen mode

And that’s it! Those are all of the logical building blocks that we will use to create a nice signup and login interface. The only thing left to do is integrate these components into a user interface, which we will do next.

Flutter Login

For convenience, we will use a flutter package called flutter_login to make our first integration quick and painless. As with all things in life, KISS.

Main.dart

import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_login/flutter_login.dart';

import 'amplifyconfiguration.dart';

void main() {
  runApp(MaterialApp(
    home: MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  // gives our app awareness about whether we are succesfully connected to the cloud
  bool _amplifyConfigured = false;

  // Instantiate Amplify
  Amplify amplifyInstance = Amplify();

  // controllers for text input
  final emailController = TextEditingController();
  final passwordController = TextEditingController();

  bool isSignUpComplete = false;
  bool isSignedIn = false;

  @override
  void initState() {
    super.initState();

    // amplify is configured on startup
    _configureAmplify();
  }

  @override
  void dispose() {
    // Clean up the controller when the widget is removed from the
    // widget tree.
    emailController.dispose();
    passwordController.dispose();

    super.dispose();
  }

  void _configureAmplify() async {
    if (!mounted) return;

    // add all of the plugins we are currently using
    // in our case... just one - Auth
    AmplifyAuthCognito authPlugin = AmplifyAuthCognito();
    amplifyInstance.addPlugin(authPlugins: [authPlugin]);

    await amplifyInstance.configure(amplifyconfig);
    try {
      setState(() {
        _amplifyConfigured = true;
      });
    } catch (e) {
      print(e);
    }
  }

  Future<String> _registerUser(LoginData data) async
  {
    try {
      Map<String, dynamic> userAttributes = {
        "email": emailController.text,
      };
      SignUpResult res = await Amplify.Auth.signUp(
          username: data.name,
          password: data.password,
          options: CognitoSignUpOptions(
              userAttributes: userAttributes
          )
      );
      setState(() {
        isSignUpComplete = res.isSignUpComplete;
        print("Sign up: " + (isSignUpComplete ? "Complete" : "Not Complete"));
      });
    } on AuthError catch (e) {
      print(e);
      return "Register Error: " + e.toString();
    }
  }

  Future<String> _signIn(LoginData data) async {
    try {
      SignInResult res = await Amplify.Auth.signIn(
        username: data.name,
        password: data.password,
      );
      setState(() {
        isSignedIn = res.isSignedIn;
      });
    } on AuthError catch (e) {
      print(e);
      return 'Log In Error: ' + e.toString();
    }
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: FlutterLogin(
          logo: 'assets/vennify_media.png',
          onLogin: _signIn,
          onSignup: _registerUser,
          onRecoverPassword: (_) => null,
          title:'Flutter Amplify'
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Of course, add the following lines to your **pubspec.yaml **to enable our new packages:

flutter_login: '<1.0.0'
rflutter_alert: '^1.0.3'
Enter fullscreen mode Exit fullscreen mode

You will need to add your own image to assets for the flutter_login logoYou will need to add your own image to assets for the flutter_login logo

Testing User Registration

To register a new user, simply use the intuitive flutter_login interface to submit a new user request to Amplify Cognito.

Use a fake email, or a real one..your choice.Use a fake email, or a real one..your choice.

Navigate to your user pool and you should see a new user that was created:

In this case, I created two usersIn this case, I created two users

Select one of the users in your pool. Notice that the status is ‘UNCONFIRMED’. In this tutorial, we will be confirming our users manually simply by tapping on the ‘Confirm User’ button. In a future tutorial, I will demonstrate how to confirm users automatically using a verification code sent to their phone or email.

Tap ‘Confirm User’ to activate the new accountTap ‘Confirm User’ to activate the new account

Testing User Login

Let’s try to login using the user that we just created.

Login and login successLogin and login success

This gif is mandatoryThis gif is mandatory

Wrapping Up

Still with me? At this point, we have a very basic authentication system for our app that leverages AWS Cognito. There are still several other topics to explore in regards to authentication, but they are beyond the scope of this tutorial. Some other challenges we need to tackle include:

  1. Authentication based on different credential types

  2. Automatic confirmation of users

  3. 2FA and custom authentication processes

I hope to cover these topics in detail in a future article. Until then, let’s continue on our journey of nailing down the basics of AWS Amplify with Flutter. Next up — analytics.

This Series

Part 1: Basic Setup

Part 2: Authentication

Part 3: Analytics

Part 4: Storage

💖 💪 🙅 🚩
thatflutterdude
FlutterArticles

Posted on September 10, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related