Get Started with Flutter Authentication

Adding authentication to a flutter app

In this section, you’ll learn how to secure a Flutter app with Auth0. You’ll take a production-ready Flutter app and add a login screen and logout functionality to it, and you’ll do it with only a fraction of the effort required to implement login and logout yourself!

You’ll be able to follow this tutorial a little more smoothly if you know the basics of Flutter, but it’s not a hard requirement. If you have experience with any modern web framework, you’ll probably be able to understand the code and learn Flutter and Dart (Flutter’s programming language) as you go.

Configure auth0

The next step is to register MJ Coffee as an application in the Auth0 dashboard.

You’ll need an Auth0 account for this step. If you don’t already have one, you can sign up for a free account. The free tier is generous enough for many small applications.

🛠 Log in to into your Auth0 account and follow the steps below to register the application:

  • 🛠 Go to the Applications section of your dashboard:
  • 🛠 Click the Create Application button:
  • 🛠 Enter a name for your application (e.g., “MJ Coffee Flutter Application”) and select the Native application type:
  • 🛠 You’ll see the Quick Start page of your newly-registered application. Go to the Connections page…

Configure the callback url for ios

The only change that you need to make in order to configure the iOS version of the app is to add a callback scheme.

🛠 To do this, open the /ios/Runner/Info.plist file. Inside the <dict> tag, add a new key, CFBundleURLTypes so that the start of the <dict> tag looks like this:



...
<dict><key>CFBundleURLTypes</key><array><dict><key>CFBundleTypeRole</key><string>Editor</string><key>CFBundleURLSchemes</key><array><string>mj.coffee.app</string></array></dict></array>
...

Creating new flutter app

Check Flutter installation to setup Flutter

Use flutter create command to create a Flutter project (here nc_basic_auth :

flutter create nc_basic_auth

Enable email link sign-in for your firebase project#

Ensure that passwordless sign-in is enabled in the project. Follow the guide here.

Enabling login on the home screen

Now that you have the underlying methods for login and initial setup, it’s time to implement similar methods for the app’s screens, whose code is in the /lib/screens/ directory.

🛠 The app’s home screen is implemented in the HomeScreen class, located in /lib/screens/home.dart.

import'package:mjcoffee/services/auth_service.dart';

Now scroll past the HomeScreen class to the _HomeScreenState class. You’ll need to make some changes to this class.

🛠 The first set of changes is to the instance variables at the start of _HomeScreenState. Change them to the following:



    bool isProgressing =false;
    bool isLoggedIn =false;
    String errorMessage ='';
    String? name;

🛠 The initState() method is just below those variables. Right now, the only thing it does is call its counterpart in the superclass.

Replace the implement init action comments with a call to initAction(). The method should look like this:

voidinitState(){initAction();super.initState();}

You’ll implement initAction() shortly.

Flutter registration & login using firebase.

Flutter Firebase ❤

In this article, we will learn how we can use Firebase Authentication in our Flutter App so that the user can sign-up and thereafter login to use our app.

What is firebase?

Firebase is a platform developed by Google for creating mobile and web applications.

What will we be making?

  1. Firstly, we will have a simple home page which has two buttons giving the users the option to either sign up, if they are using our app for the first time or sign in if he has visited our app before.
  2. On our sign-up page, we can ask for his required credentials like email-id and password. We can also ask for name, phone number, and also other credentials but for the sole purpose of learning how to use firebase authentication in our flutter app, email-id and password should be enough.
  3. On our login page, we will ask for his email id and password to direct him to our home page.
  4. Both the login page and sign-up page will validate the user credentials using the firebase authentication and direct them to our home page.
  5. We will have a simple home page to welcome the user right after the procedure of sign-up/login is complete.
  1. main.dart (default, will be there)
  2. welcome_screen.dart (To give the user the option for sign up or log in)
  3. login_screen.dart
  4. signup_screen.dart
  5. home_screen.dart

Now first to authenticate our app with firebase authentication we need to go to our google firebase console and start a new project. Follow this link to go to your fire up your firebase console https://firebase.google.com/

After opening your firebase console click on add/start a new project.

Project Screen

You can give your project any name you wish and hit continue.

Enable the google analytics for this project and hit continue.

Select Default Account for Firebase and Create Project.

It might 10–15 seconds and then you will be all set to use Firebase for authentication of your flutter app.

There was no such fuss about doing all that was it?

In this article we will learn how to set up our firebase project for android.

Click on the litter android button on this screen of your firebase project and you will be directed to a page to set up your application for android.

We need to give an android package name to our android app, now be careful about this it can’t be any name as it suggests your android package name is in your Flutter Project at the app-level `build.gradle`, file, you need to head over there and locate for the `applicationId`, tag in your `build.gradle`, file, that will be the name you need to put in your Android Package name.

After completing this step you click on Register App.

After registering your app you need to download the google-services.json file. Now after downloading this file make sure you drag or place this file in the android/app folder of your flutter project.

Now there is few other things we need to do before we are done with the settings of our android app.

Open up your project level `build.gradle`, file and add then copy the dependencies to your `build.gradle`, file.

Then we need to open our app level `build.gradle`, file and copy and add the dependencies to our app level `build.gradle`, file.

We are going to copy this line-

implementation `com.google.firebase:firebase-analytics`, and add this to our dependency.

We are also going to copy this line — apply plugin: `com.google.gms.google-services`, which implements our google services json file and paste it right at the end of our app/build.gradle file.

Also while you are in your app/build.gradle file I would suggest you to make few additions at some places to avoid any error you might encounter in the future while running your app.

First, we will make changes in our default config tag as follows:

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "iamharsh.login_signup"
minSdkVersion 16
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true //add this line
}

Secondly, we will make changes in the dependencies tag as follows:

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.android.support:multidex:1.0.3' //add this line
}

Now you are all set up to use firebase authentication in your project.

We will need two modules to use firebase in your flutter project for authentication

  1. firebase_core– A Flutter plugin to use the Firebase Core API, which enables connecting to multiple Firebase apps.
  2. firebase_auth– A Flutter plugin to use the Firebase Authentication API.

Now we will need to update our pubsec.yaml file and update the dependencies to use these modules.

dependencies:
flutter:
sdk: flutter

cupertino_icons: ^1.0.0
firebase_core: ^0.5.3
firebase_auth: ^0.18.4 1
modal_progress_hud: ^0.1.3

This is how your dependencies should look like in your pubspec.yaml file. After updating the dependencies make sure you click on Pub Get.

In our main.dart file we will be defining the initial route, routes and navigation for navigating to other pages by using dart maps.

Here’s how our main.dart file would look like-

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'welcome_screen.dart';
import 'home_screen.dart';
import 'signup_screen.dart';
import 'login_screen.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: 'welcome_screen',
routes: {
'welcome_screen': (context) => WelcomeScreen(),
'registration_screen': (context) => RegistrationScreen(),
'login_screen': (context) => LoginScreen(),
'home_screen': (context) => HomeScreen()

},
);
}
}

Now we need to design a welcome screen for the user to either direct the user to the login screen page or the sign-up/register screen page.

We can design the UI for our screen somewhat like this-

You might use a Flat button or you can make a customized button like I have and use that instead.

Here is the code for the customized button if you want to use it in your code.

import 'package:flutter/material.dart';

class RoundedButton extends StatelessWidget {
RoundedButton(
{@required this.colour, @required this.title, @required this.onPressed});
final Color colour;
final String title;
final Function onPressed;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
elevation: 5.0,
color: colour,
borderRadius: BorderRadius.circular(30.0),
child: MaterialButton(
onPressed: onPressed,
//Go to login screen.
minWidth: 200.0,
height: 42.0,
child: Text(
title,
style: TextStyle(color: Colors.white),
),
),
),
);
}
}

So you can create a separate dart file and use the above code to create your own button.

Here’s the code for our welcome screen

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

class WelcomeScreen extends StatefulWidget {
@override
_WelcomeScreenState createState() => _WelcomeScreenState();
}

class _WelcomeScreenState extends State<WelcomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
RoundedButton(
colour: Colors.lightBlueAccent,
title: 'Log In',
onPressed: () {
Navigator.pushNamed(context, 'login_screen');
},
),
RoundedButton(
colour: Colors.blueAccent,
title: 'Register',
onPressed: () {
Navigator.pushNamed(context, 'registration_screen');
}),
]),
));
}
}

Now we before we look into the code for our login and sign up screen we need to do one little thing go to your firebase project and under the authentication tab of your project go to the sign-in method tab and there you find a email/provider tab switch it on and hit save.

Now we will be dealing with the heart of our app that is to creating an account and signing the user in.

In both our sign-up and login page we will have two fields in which the user will enter or create his/her email and password and login into our database. The account details of the user will be stored under the users’ tab of our firebase project.

This is how our Sign Up screen would look like-

First let’s take a look at the code for our sign up screen-

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'rounded_button.dart';

//code for designing the UI of our text field where the user writes his email id or password

const kTextFieldDecoration = InputDecoration(
hintText: 'Enter a value',
hintStyle: TextStyle(color: Colors.grey),
contentPadding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(32.0)),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightBlueAccent, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(32.0)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightBlueAccent, width: 2.0),
borderRadius: BorderRadius.all(Radius.circular(32.0)),
),
);

class RegistrationScreen extends StatefulWidget {
@override
_RegistrationScreenState createState() => _RegistrationScreenState();
}

class _RegistrationScreenState extends State<RegistrationScreen> {
final _auth = FirebaseAuth.instance;
String email;
String password;
bool showSpinner = false;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
onChanged: (value) {
email = value;
//Do something with the user input.
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Enter your email')),
SizedBox(
height: 8.0,
),
TextField(
obscureText: true,
textAlign: TextAlign.center,
onChanged: (value) {
password = value;
//Do something with the user input.
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Enter your Password')),
SizedBox(
height: 24.0,
),
RoundedButton(
colour: Colors.blueAccent,
title: 'Register',
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
final newUser = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.pushNamed(context, 'home_screen');
}
} catch (e) {
print(e);
}
setState(() {
showSpinner = false;
});
},
)
],
),
),
),
);
}
}

Here we first create a variable _auth for our firebase instance and declare it as final because we won’t be changing it at all. This will allow us to work with our firebase authentication procedure and we can now create a user or sign in a user as we have done in the above code segment that we have created a user account, with the function createUserWithEmailAndPassword, now the user can create an email id and password and password for himself. If there is something wrong while creating an account firebase will throw an exception

The code for logging in is the almost identical only difference being here we use the firebase instance to sign the user into our app with the email id and password he has already created and has registered himself on our app.

This is how our login screen would look like-

Here’s the code for our login screen-

import 'package:firebase_auth/firebase_auth.dart';
import 'rounded_button.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:flutter/material.dart';

//code for designing the UI of our text field where the user writes his email id or password

const kTextFieldDecoration = InputDecoration(
hintText: 'Enter a value',
hintStyle: TextStyle(color: Colors.grey),
contentPadding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(32.0)),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightBlueAccent, width: 1.0),
borderRadius: BorderRadius.all(Radius.circular(32.0)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.lightBlueAccent, width: 2.0),
borderRadius: BorderRadius.all(Radius.circular(32.0)),
));

class LoginScreen extends StatefulWidget {
@override
_LoginScreenState createState() => _LoginScreenState();
}

final _auth = FirebaseAuth.instance;

class _LoginScreenState extends State<LoginScreen> {
String email;
String password;
bool showSpinner = false;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
onChanged: (value) {
email = value;
//Do something with the user input.
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Enter your email',
)),
SizedBox(
height: 8.0,
),
TextField(
obscureText: true,
textAlign: TextAlign.center,
onChanged: (value) {
password = value;
//Do something with the user input.
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Enter your password.')),
SizedBox(
height: 24.0,
),
RoundedButton(
colour: Colors.lightBlueAccent,
title: 'Log In',
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
final user = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (user != null) {
Navigator.pushNamed(context, 'home_screen');
}
} catch (e) {
print(e);
}
setState(() {
showSpinner = false;
});
}),
],
),
),
),
);
}
}

So with this our procedure of creating a user account on firebase and signing in the user with his credentials is complete.

Now the only thing left is our home screen where the user will be headed after creating an account or logging in. For the purpose of this article, we will keep our home screen relatively simple and it will have just some normal text welcoming the user.

This is our how our home screen will look like-

It will just display at the center of the screen “Welcome User”. Also if you notice there is a cross icon button on the top right corner of our app bar, that will actually sign the user out of our app. I have created a specific function to execute that functionality.

Here’s the code for our home screen-

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

User loggedinUser;

class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
final _auth = FirebaseAuth.instance;

void initState() {
super.initState();
getCurrentUser();
}

//using this function you can use the credentials of the user
void getCurrentUser() async {
try {
final user = await _auth.currentUser;
if (user != null) {
loggedinUser = user;
}
} catch (e) {
print(e);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pop(context);

//Implement logout functionality
}),
],
title: Text('Home Page'),
backgroundColor: Colors.lightBlueAccent,
),
body: Center(
child: Text(
"Welcome User",
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
);
}
}

So with this our app is done and now we can create a user account and sign the user in or sign out.

You can check out the source code here- https://github.com/harshlohia11/flutter-signup-login.git

This was so cool, right?

That’s the simplest explanation I could write, there are of course the scenes things, but don’t bother yourself with them now.

Thanks for reading.

In the next article, we will discuss how we can sign the user in with his google account!

Get the project, configure it, and run it

🛠 Open the repository for the MJ Coffee app and download the source from the main branch. This contains a fully functioning app that is ready for you to add Auth0 authentication/authorization and chat.

🛠 If you want to build the app for iOS, you’ll need to specify your own development team for the build process. Open the /ios/Runner.xcworkspace/ file with Xcode, select the Runner project, then the Runner target, open the Signing & Capabilities tab, and select your team in the Team drop-down menu:

🛠 Confirm that the app works by running it. Open a command-line interface, navigate to the project’s root directory, and enter flutter run.

Flutter will compile the project and run it on any mobile device connected to your computer or any mobile device emulator running on it. If it can’t find any of those, it will run a mobile device emulation in a browser window.

You will see the app’s home screen:

Handle the id token with parseidtoken

Your Flutter application will get an ID token that it will need to parse as a Base64 encoded string into a Map object. You’ll perform that action inside the parseIdToken() method.

Check this JSON payload to get a better sense of what a decoded ID token looks like:

Integrating auth0 with flutter

Since Auth0 is a standard OAuth 2.0 authorization server, you can utilize any standard OpenID Connect SDK to authenticate against Auth0. One of them is flutter_appauth, a wrapper around the AppAuth SDK for native applications. You will need to integrate it into your application.

🛠 Open the /lib/services/auth_service.dart file and update it to import the necessary libraries as well as instantiate FlutterAppAuth and FlutterSecureStorage:

Integration with appauth

The very first step in setting up AppAuth against your authorization server is to configure OAuth 2.0 endpoint URLs. Your sample application involves three endpoints:

Layers of sessions

Every login requires logout! It’s more complicated than it looks since there are typically three-session layers you need to consider:

Logging in

🛠 If you’ve made it this far, you’ve done well, and it’s now time to see what you’ve achieved so far. Make sure your emulators or devices are active and stop any earlier versions of this app. Once you’ve done that, run the app using this command:

flutter run -d all --dart-define=AUTH0_DOMAIN=[YOUR DOMAIN] --dart-define=AUTH0_CLIENT_ID=[YOUR CLIENT ID]

Once the app is loaded, tap on the “Login | Register” button.

On iOS, when you run the app for the first time, you will see a prompt like this:

Other sign-in methods#

Firebase also supports authenticating with external provides. To learn more, view the documentation for your authentication method:

Prerequisites

Before getting started with this article, you need a working knowledge of Flutter. If you need help getting started, you can follow the codelabs on the Flutter website.

You also need to have the following installations in your machine:

Provide the domain and client id to the app

You will need to use the domain and client ID that you copied from the Settings page in your Flutter application. You can either store these values in constant variables in the app’s code, or you can pass these values to the app by providing them as –dart-define arguments when you run it.

Rather than store this sensitive information in your code (which is a big security risk), I suggest that you supply the app with these values as –dart-define arguments when you run it.

🛠 To do this in Terminal or PowerShell, use this command:

flutter run -d all --dart-define=AUTH0_DOMAIN={YOUR DOMAIN} --dart-define=AUTH0_CLIENT_ID={YOUR CLIENT ID}

You can optionally have your editor of choice provide these values. For example, you can have Visual Studio Code pass these additional –dart-define values by adding them to the args field of your launch configuration file (/.vscode/launch.json):

Run the application

Launch either the iOS simulator or Android emulators, then run the application on all available devices like so:

flutter run -d all

I have feedback or ran into an issue

Sign-in#

To sign-in to an existing account, call the signInWithEmailAndPassword() method:

Once successful, if you are listening to changes in authentication state, a new event will be sent to your
listeners.

Take a quick tour of the app

🛠 Tap the Login | Register button. Right now, there is no login functionality, so the app immediately takes you to the Menu screen:

The access token, refresh token, and id token

You can use the Access Token to access APIs. Clients can’t decode this token, which is all right since it only means something to the API’s authorization server.

What you’ll learn and build

While you could create a new Flutter project and implement everything you will learn in this tutorial, adding authentication to an existing production-ready app is pretty common. I’ll provide a production-ready app, MJ Coffee, which you’ll secure by adding authentication.

Conclusion

Congratulations! You have just integrated Auth0-powered login and logout into the MJ Coffee app.

In an upcoming section, you will continue to add authentication features to the app. You’ll learn more about Refresh Token rotation, managing the branding that appears in the login box, roles and adding social login via Apple and Google accounts.

Install dependencies

This Flutter project requires three main dependencies:

Next, open the pubspec.yaml file located under the project root directory. Specify your project dependencies by replacing the dependencies section with the snippet below:

Configure android dependencies and callback url

flutter_secure_storage has a minSdkVersion:18 dependency, so you need to bump up the default minSdkVersion:16 provisioned by the flutter create scaffolding command.

Update the android/app/build.gradle file as follows:

    defaultConfig {
        applicationId "com.auth0.flutterdemo"
        minSdkVersion 18
        targetSdkVersion 28
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        manifestPlaceholders =['appAuthRedirectScheme':'com.auth0.flutterdemo']}

Notice the added lines to insert the appAuthRedirectScheme variable into your defaultConfig section. The value of appAuthRedirectScheme must be in lower case letters.

Handling the app’s initial state

The only thing missing is handling the authentication state when the app is launched. You might want to be able to silently login and retrieve a new Access Token if a Refresh Token is available.

🛠 Let’s add a new method, init(), to deal with the app’s initial state. Implement this method by adding the following to AuthService:



  Future<bool>init()async{final storedRefreshToken =await secureStorage.read(key: REFRESH_TOKEN_KEY);if(storedRefreshToken ==null){returnfalse;}try{final TokenResponse? result =await appAuth.token(TokenRequest(
          AUTH0_CLIENT_ID,
          AUTH0_REDIRECT_URI,
          issuer: AUTH0_ISSUER,
          refreshToken: storedRefreshToken,),);final String setResult =await_setLocalVariables(result);return setResult =='Success';}catch(e, s){print('error on Refresh Token: $e - stack: $s');returnfalse;}}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *