auth 4.0.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 86

Auth #

This library package works with four plugins:

All four are used to log into a Firebase backend. If you're familiar with these plugins, you'll be able to quickly use this class library.

Installing #

I don't always like the version number always suggested in the 'Installing' page. Instead, always go up to the 'major' semantic version number when installing my library packages. This means always entering a version number trailing with two zero, '.0.0'. This allows you to take in any 'minor' versions introducing new features as well as any 'patch' versions that involves bugfixes. Semanitic version numbers are always in this format: major.minor.patch.

  1. patch - I've made bugfixes
  2. minor - I've introduced new features
  3. major - I've essentially made a new app. It's broken backwards-compatibility and has a completely new the user experience. You won't get this version until you increment the major number in the pubspec.yaml file.

And so, in this case, add this to your package's pubspec.yaml file instead:

dependencies:
  auth:^4.0.0

For more information on this topic, read the article, The importance of semantic versioning.

How it Works #

Below are a series of screenshots depicting how to initialize and authenticate or 'sign in' an individual into your app's Firebase database using a either an email and password or a Google account. The following will sign in 'silently' (i.e. automatically if the user had already signed in in the past.). Note, settings are passed as parameters in the screenshot below. 09inistate These examples have the class library called in the State object's iniState() function, but, of course, you could instead 'initialize' the class library in the initState() function and then 'sign in' elsewhere. Below, the init() function is used instead just to initialize the class library. authinit auth3 anyomous google properties

Facebook #

Even if you've no intention of allowing users to use Facebook to log in, you will have to modify a few files any way so to use this library package. You can then ignore these files as they just need to be there. If you don't add to these three files, you'll get the following error when trying to use this Auth package: "The SDK has not been initialized, make sure to call FacebookSdk.sdkInitialize() first." faceSDKerror

On The Android Side #

You must acknowledge to Android that the Facebook SDK is being utilized. Hence, a means to initialize it is required. So, go to the 'Android Manifest file' (android/app/src/main/AndroidManifest.xml) and add the following after the first tag, but before the last tag, . See below. facebookManifest You can copy and paste the code here:

<meta-data android:name="com.facebook.sdk.ApplicationId"
    android:value="@string/facebook_app_id"/>

<activity android:name="com.facebook.FacebookActivity"
    android:configChanges=
            "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
    android:label="@string/app_name" />

<activity
    android:name="com.facebook.CustomTabActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="@string/fb_login_protocol_scheme" />
    </intent-filter>
</activity>

Now go to the 'styles' (android/app/src/main/res/values/styles.xml) file and add the following:

    <string name="app_name">Your App Name here.</string>
<!-- Replace "000000000000" with your Facebook App ID here. -->
    <string name="facebook_app_id">000000000000</string>
<!-- Replace "000000000000" with your Facebook App ID here.    -->
    <string name="fb_login_protocol_scheme">fb000000000000</string>

With that, you can get on with your app even if you're not going to log in with Facebook. Here's what it would possibly look like in your particular file: facebookresfile Note: Place this file in .gitignore so not to save this Facebook App ID numbers on a public Github repository.

Setup Facebook Login #

You will have to go to your Facebook Developers account and create or select the app you'll use. facebookDevelopers Under Settings, click on the show button to copy down your App ID and App Secret those later (Firebase will need them). AppSecret

Click on the 'Quickstart' link below to set up Facebook on the Android side: quickStart The following steps in particular will get your app working with Facebook: 1. Select an App or Create a New App 4. Edit Your Resources and Manifest 5. Associate Your Package Name and Default Class with Your App 6. Provide the Development and Release Key Hashes for Your App

Tell Firebase #

Remember, all this effort is to connect to a backend Firebase database. You some things to do in the Firebase Projects Console. FirebaseProjects You'll have to go into the Sign-in method tab and enable the Facbook option and any other options you may wish to use to log into this Firebase app: signInProviders

Use Twitter #

You can use Twitter as well if you want to. You'll just need to create an app on Twitter and then supply the Consumer API keys to this library package. TwitterDeveloper keysTokens

On Medium #

This is a class library is covered again in the Medium article, Auth in Flutter. AuthArticle

Other Dart Packages #

packages Other Dart packages from the author can also be found at Pub.dev

4.0.0 #

October 02, 2019

  • removed signIn()
  • new signInSilently()
  • new signInWithGoogleSilently()
  • new signInWithFacebook()
  • new signInWithFacebookSilently()
  • new signInFacebook()
  • new signInWithTwitter()
  • new signInWithTwitterSilently()
  • new signInTwitter()
  • new addListen(f)
  • deprecated googleListener(f)
  • new addListener(f)
  • deprecated fireBaseListener(f)
  • createUserWithEmailAndPassword() allowed if logged in
  • addListener(f) in signInAnonymously()
  • addListener(f) in signInWithCredential()
  • addListener(f) in signInWithCustomToken()
  • addListener(f) in signInWithEmailAndPassword() October 01, 2019
  • user = await currentUser();
  • plugin flutter_twitter
  • plugin flutter_facebook_login
  • delete folder src\oauth

3.2.0 #

  • Provided new functions: getIdToken(); updatePhoneNumberCredential(); linkWithCredential(); updatePassword(); sendEmailVerification(); updateProfile(); reload(); reauthenticateWithCredential();
    delete(); unlinkFromProvider(); updateEmail();

3.1.1 #

  • set listen(GoogleListener f) => _googleListeners.add(f);

3.1.0 #

  • void return type in some functions.
  • Introduced the setters, listener and listen.

3.0.0 #

August 06, 2019

  • Removed parameters onError, onDone(), and cancelOnError from the Constructor
  • Introduced getEventErrors() and eventErrors
  • CustomAlertDialog class in example app

2.1.0 #

August 02, 2019

  • Introduced signedInGoogle(), signedInFirebase()
  • Adjusted example main.dart

2.0.0 #

August 02, 2019

  • Abandoned the Singleton design pattern
  • Factory constructor to ensure only one Auth instance.
  • Renamed signIn functions.

1.3.1 #

August 02, 2019

  • Removed properties: signInOption scopes hostedDomain onError, onDone, cancelOnError
  • Set{} for list of listeners
  • Rearranged code for readability

1.3.0 #

August 02, 2019

  • async isSignedIn(), isLoggedIn()
  • Library-private _initFireBase()
  • _setUserFromFireBase() in _listFireBaseListeners()
  • _setFireBaseUserFromGoogle() in _listGoogleListeners()
  • Introduced IdTokenResult
  • if (ex is! Exception) {

1.2.1 #

July 29, 2019

  • Latest firebase_auth version
  • Format code
  • signInWithTwitter()

1.2.0 #

  • Include the new classes AuthResult and AdditionalUserInfo from firebase_auth

1.1.0+1 #

Mar. 21, 2019

  • move FlutterOAuth library to oauth directory

1.1.0 #

Mar. 21, 2019

  • incorporated Joe Birch's FlutterOAuth library
  • introduced signInWithFacebook() function

1.0.1 #

Mar. 07, 2019

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

1.0.0 #

Mar. 07, 2019

  • Added signInWithCredential, linkWithCredential, fetchSignInMethodsForEmail
  • Breaking Change Removed signInWithFacebook, signInWithTwitter, signInWithGoogle,
  • Breaking Change linkWithEmailAndPassword, linkWithGoogleCredential, linkWithFacebookCredential

0.1.1 #

Jan. 17, 2019

  • await _setFireBaseUserFromGoogle(currentUser);

0.1.0 #

Dec. 10, 2018

  • Change semantic version number to convey development phase.

0.0.3 #

  • await _user?.reload();

0.0.2 #

  • Format code with dartfmt

0.0.1 #

  • Initial github release

example/main.dart

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

import 'package:flutter/services.dart' show SystemChannels, TextInputType;

import 'package:google_sign_in/google_sign_in.dart' show GoogleUserCircleAvatar;

import 'package:auth/auth.dart' show Auth;

void main() {
  runApp(
    MaterialApp(
      home: SignInDemo(),
      debugShowCheckedModeBanner: false,
    ),
  );
}

class SignInDemo extends StatefulWidget {
  @override
  State createState() => SignInDemoState();
}

class SignInDemoState extends State<SignInDemo>
    with SingleTickerProviderStateMixin {
  Auth auth;
  bool loggedIn = false;
  TabController tabController;
  String errorMessage = "";

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

    tabController = TabController(length: 2, vsync: this);

    auth = Auth.init(
        scopes: [
          'email',
          'https://www.googleapis.com/auth/contacts.readonly',
        ],
        listener: (user) {
          loggedIn = user != null;
          errorMessage = auth.message;
          setState(() {});
        });

    auth.signInSilently(
      listen: (account) {
        loggedIn = account != null;
        errorMessage = auth.message;
        setState(() {});
      },
      listener: (user) {
        final test = user != null;
      },
    );

    auth.isLoggedIn().then((isIn) {
      loggedIn = isIn;
    });
  }

  @override
  void dispose() {
    /// Important to dispose of the Auth's resources.
    auth.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("Sign In Demo"),
          bottom: TabBar(
            tabs: [
              const Tab(text: "Sign In"),
              const Tab(text: "Results"),
            ],
            controller: tabController,
          ),
        ),
        body: Center(
          child: TabBarView(
            controller: tabController,
            children: <Widget>[
              ConstrainedBox(
                constraints: const BoxConstraints.expand(),
                child: _buildBody(),
              ),
              ConstrainedBox(
                constraints: const BoxConstraints.expand(),
                child: _authResults,
              ),
            ],
          ),
        ));
  }

  Widget _buildBody() {
    if (loggedIn) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          ListTile(
            leading: auth.signedInGoogle()
                ? GoogleUserCircleAvatar(
                    identity: auth.googleUser,
                  )
                : Text(''),
            title: Text(auth.displayName),
            subtitle: Text(auth.email),
          ),
          const Text("Signed in successfully."),
          signInErrorMsg,
          RaisedButton(
            child: const Text('Sign Out of Firebase'),
            onPressed: () {
              auth.signOut();
            },
          ),
          RaisedButton(
            child: const Text('Sign Out & Disconnect'),
            onPressed: () {
              auth.disconnect();
            },
          ),
          RaisedButton(
            child: const Text('Just Quit'),
            onPressed: () {
              SystemChannels.platform.invokeMethod('SystemNavigator.pop');
            },
          ),
        ],
      );
    } else {
      // This function is called by every RaisedButton widget.
      Function signInFunc = (signIn) {
        if (signIn) {
          errorMessage = "";
        } else {
          errorMessage = auth.message;
        }
        setState(() {});
      };

      return Column(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          const Text("You are not currently signed in."),
          signInErrorMsg,
          RaisedButton(
            child: const Text('Sign In With Facebook'),
            onPressed: () {
              auth.signInWithFacebook().then(signInFunc).catchError((err) {
                if (err is! Exception) err = err.toString();
                errorMessage = auth.message;
              });
            },
          ),
          RaisedButton(
            child: const Text('Sign In With Twitter'),
            onPressed: () {
              auth
                  .signInWithTwitter(
                      key: "ab1cefgh23KlmnOpQ4STUVWx5",
                      secret:
                          "ab1cefgh23KlmnOpQ4STUVWx5y6ZabCDe7ghi8jKLMnOP9qRst")
                  .then(signInFunc)
                  .catchError((err) {
                if (err is! Exception) err = err.toString();
                errorMessage = auth.message;
              });
            },
          ),
          RaisedButton(
            child: const Text('Sign In With Google'),
            onPressed: () {
              auth.signInWithGoogle().then(signInFunc).catchError((err) {
                if (err is! Exception) err = err.toString();
                errorMessage = auth.message;
              });
            },
          ),
          RaisedButton(
            child: const Text('Log in anonymously'),
            onPressed: () {
              auth.signInAnonymously().then(signInFunc).catchError((err) {
                if (err is! Exception) err = err.toString();
                errorMessage = auth.message;
              });
            },
          ),
          RaisedButton(
            child: const Text('Sign in with Email & Password'),
            onPressed: () async {
              List<String> ep = await dialogBox(context: context);
              if (ep == null || ep.isEmpty) return;
              auth
                  .signInWithEmailAndPassword(email: ep[0], password: ep[1])
                  .then(signInFunc)
                  .catchError((err) {
                if (err is! Exception) err = err.toString();
                errorMessage = auth.message;
              });
            },
          ),
        ],
      );
    }
  }

  Widget get _authResults => ListView(
        padding: const EdgeInsets.all(30.0),
        itemExtent: 80.0,
        children: <Widget>[
          Text("uid: ${auth.uid}"),
          Text("name: ${auth.displayName}"),
          Text("photo: ${auth.photoUrl}"),
          Text("new login: ${auth.isNewUser}"),
          Text("user name: ${auth.username}"),
          Text("email: ${auth.email}"),
          Text("email verified: ${auth.isEmailVerified}"),
          Text("anonymous login: ${auth.isAnonymous}"),
          Text("permissions: ${auth.permissions}"),
          Text("id token: ${auth.idToken}"),
          Text("access token: ${auth.accessToken}"),
          Text("information provider: ${auth.providerId}"),
          Text("expire time: ${auth.expirationTime}"),
          Text("auth time: ${auth.authTime}"),
          Text("issued at: ${auth.issuedAtTime}"),
          Text("signin provider: ${auth.signInProvider}"),
        ],
      );

  Widget get signInErrorMsg => Container(
      padding: const EdgeInsets.all(10),
      child: Center(
          child: RichText(
              text: TextSpan(
        text: errorMessage,
        style: const TextStyle(color: Colors.red),
      ))));
}

// Creates an alertDialog for the user to enter their email
Future<List<String>> dialogBox({
  Key key,
  @required BuildContext context,
  bool barrierDismissible = false,
}) {
  return showDialog<List<String>>(
    context: context,
    barrierDismissible: barrierDismissible, // user must tap button!
    builder: (BuildContext context) {
      return CustomAlertDialog(
        key: key,
        title: "Email & Password",
      );
    },
  );
}

class CustomAlertDialog extends StatefulWidget {
  final String title;
  const CustomAlertDialog({Key key, this.title}) : super(key: key);

  @override
  CustomAlertDialogState createState() => CustomAlertDialogState();
}

class CustomAlertDialogState extends State<CustomAlertDialog> {
  final _resetKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  bool _resetValidate = false;
  bool _hidePassword = true;

  @override
  Widget build(BuildContext context) {
    return Container(
      child: AlertDialog(
        title: Text(widget.title),
        elevation: 20.0,
        content: SingleChildScrollView(
          child: Form(
            key: _resetKey,
            autovalidate: _resetValidate,
            child: ListBody(
              children: <Widget>[
                const Text(
                  "Email Address & Password.",
                  style: const TextStyle(fontSize: 14.0),
                ),
                Padding(
                  padding: const EdgeInsets.all(10.0),
                ),
                Column(
                  children: <Widget>[
                    Row(mainAxisSize: MainAxisSize.min, children: <Widget>[
                      Padding(
                        padding: const EdgeInsets.only(top: 8.0),
                        child: const Icon(
                          Icons.email,
                          size: 20.0,
                        ),
                      ),
                      SizedBox(
                        width: 250,
                        child: TextFormField(
                          validator: validateEmail,
                          controller: _emailController,
                          keyboardType: TextInputType.emailAddress,
                          autofocus: true,
                          decoration: InputDecoration(
                              border: InputBorder.none,
                              hintText: 'Email',
                              contentPadding:
                              const EdgeInsets.only(left: 70.0, top: 15.0),
                              hintStyle: const TextStyle(
                                  color: Colors.black, fontSize: 14.0)),
                          style: const TextStyle(color: Colors.black),
                        ),
                      )
                    ]),
                    SizedBox(
                      width: 200,
                      child: TextFormField(
                        validator: (String value) {
                          if (value.length == 0 || value.isEmpty)
                            return "Password required.";
                          return null;
                        },
                        keyboardType: TextInputType.text,
                        controller: _passwordController,
                        obscureText:
                            _hidePassword, //This will obscure text dynamically
                        decoration: InputDecoration(
                          labelText: 'Password',
                          hintText: 'Enter your password',
                          // Here is key idea
                          suffixIcon: IconButton(
                            icon: Icon(
                              // Based on passwordVisible state choose the icon
                              _hidePassword
                                  ? Icons.visibility_off
                                  : Icons.visibility,
                              color: Theme.of(context).primaryColorDark,
                            ),
                            onPressed: () {
                              // Update the state i.e. toogle the state of passwordVisible variable
                              setState(() {
                                _hidePassword = !_hidePassword;
                              });
                            },
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
        actions: <Widget>[
          FlatButton(
            child: const Text(
              'CANCEL',
              style: const TextStyle(color: Colors.black),
            ),
            onPressed: () {
              Navigator.of(context).pop();
            },
          ),
          FlatButton(
            child: const Text(
              'SEND EMAIL',
              style: const TextStyle(color: Colors.black),
            ),
            onPressed: () {
              _onPressed();
            },
          ),
        ],
      ),
    );
  }

  void _onPressed() {
    bool valid = true;

    if (!_resetKey.currentState.validate()) {
      valid = false;
    }

    if (valid) {
      Navigator.of(context)
          .pop([_emailController.text, _passwordController.text]);
    } else {
      _resetValidate = true;
      setState(() {});
    }
  }
}

String validateEmail(String value) {
  String pattern =
      r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
  RegExp regExp = RegExp(pattern);
  if (value.length == 0) {
    return "Email is required";
  } else if (!regExp.hasMatch(value)) {
    return "Invalid Email";
  } else {
    return null;
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  auth: ^4.0.0

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:auth/auth.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
73
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
86
Learn more about scoring.

We analyzed this package on Oct 19, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.5.1
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.3.0 <3.0.0
firebase_auth ^0.14.0 0.14.0+5
flutter 0.0.0
flutter_facebook_login ^3.0.0 3.0.0
flutter_twitter ^1.0.0 1.1.3
google_sign_in ^4.0.0 4.0.7
Transitive dependencies
collection 1.14.11 1.14.12
firebase_core 0.4.0+9
meta 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test