Skip to content

Login

Description

This module provides screens and functionality to add Login, SignUp and password recovery to your Flutter app.

You can also extend the module to support new login providers.

Supported Providers

At this moment, the module support the following providers:

You can enable or disable providers in the configuration phase.

Dependencies

Base module

Email module

Google module

Twitter Module

Get started

  1. Download the module from our shop and extrat it somewhere. You will have 6 folders:
  • login_auth_email
  • login_auth_google
  • login_auth_module
  • login_auth_x
  • login_module
  • example
  1. Create a folder called vendors in your project

  2. Copy the modules you want to use to the vendors/ folder. You will need at least login_module and login_auth_module. Other Auth providers are optional, but you need at least one.

  3. Add the dependencies in your’s app pubspec.yml:

dependencies:
flutter:
sdk: flutter
login_module:
path: vendors/login_module
login_auth_module:
path: vendors/login_auth_module
login_auth_google:
path: vendors/login_auth_google
login_auth_x:
path: vendors/login_auth_x
login_auth_email:
path: vendors/login_auth_email

How to configure the module

This module have two dependencies:

  • An Auth instance that needs to be registered.
  • A Theme extension that needs to be provided in the theme definition

Providing an Auth instance

The module provides a AuthRegister class so you can provide the Auth class.

The first thing you need to do import the main module and the auth providers you want to use:

# Mandatory
import 'package:login_module/login_module.dart';
import 'package:login_auth_module/login_auth_module.dart';
# Optional
import 'package:login_auth_email/login_auth_email.dart';
import 'package:login_auth_google/login_auth_google.dart';
import 'package:login_auth_x/login_auth_x.dart';

Then, register the instance:

void main() {
AuthRegister.register(Auth({
GoogleAuthLogic(),
EmailAuthLogic(),
XAuthLogic(
apiKey: "<your api key>",
apiSecretKey: "<your api key secret>",
redirectURI: "appname://",
),
}));
runApp(MyApp());
}

Now you can call runApp to start your app.

Customize module via Theme extension

A theme extension is a tool that Flutter provides to add extra information to a ThemeData so you have it available everywhere. We use a theme extension so you can configure all the visual customizations in just one place.

To provide an extension you should crete an instance of the provided LoginThemeExtension and add it to the current theme:

Widget build(BuildContext context) {
return MaterialApp(
title: 'Login Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color.fromARGB(255, 14, 132, 123),
),
useMaterial3: true,
inputDecorationTheme: const InputDecorationTheme(
hintStyle: TextStyle(color: Colors.white70),
),
extensions: <ThemeExtension<dynamic>>[
LoginThemeExtension(
backgroundImage: "assets/images/pexels-20367724.jpg",
),
],
),
home: LoginScreen(),
);
}

This will set the background image of all the login flow screens to the same image.

Flutter Router and Current User

You can read the current logged in user, if any, by getting the instance of Auth and look for changes.

This is very useful if you also use it in convination with GoRouter, so you can redirect the user to the login flow if needed or to the home if already it’s logged in as show next:

final router = GoRouter(
refreshListenable: AuthRegister.isLoggedInListenable,
routes: [
GoRoute(
path: '/',
redirect: (context, state) {
if (!AuthRegister.instance.isLoggedIn()) return '/login';
return null;
},
builder: (context, state) => const HomeScreen(),
routes: [
GoRoute(
path: 'profile',
builder: (context, state) => const ProfileScreen(),
),
],
),
GoRoute(
path: '/login',
builder: (context, state) => LoginScreen(),
redirect: (context, state) {
if (AuthRegister.instance.isLoggedIn()) return '/';
return null;
},
),
],
);

The refreshListenable will make the router to reevaluate the current route if something change in the log in status.

The redirect will ensure that if the user is not logged in, the user is redirected and can’t see other screens. This is special important for Flutter for web.

Once you have your router defined, you can just use it in the app:

@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerDelegate: router.routerDelegate,
routeInformationProvider: router.routeInformationProvider,
routeInformationParser: router.routeInformationParser,
);
}

Using Flutter Bloc

If you want to use Flutter Bloc with the login module you can do it with a custom bloc to handle the login.

Login State

First, create the state class so the UI can listen for state changed in the login state:

// This is the login_state.dart file
part of 'login_bloc.dart';
class LoginState extends Equatable {
final bool isLoggedIn;
const LoginState(this.isLoggedIn);
@override
List<Object?> get props => [isLoggedIn];
}

Login Event

And you will also need a bloc event class to handle login events:

// This is the login_event.dart file
part of 'login_bloc.dart';
class LoginEvent extends Equatable {
final AuthUser? user;
const LoginEvent(this.user);
@override
List<Object?> get props => [user];
}

Login Block

Last, create a new bloc class and add the logic to listen to the auth currentUser stream:

// This is the login_bloc.dart class
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:signals/signals_flutter.dart';
import 'package:login_auth_module/login_auth_module.dart';
part 'login_event.dart';
part 'login_state.dart';
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final Auth auth = AuthRegister.instance;
EffectCleanup? disposeEffect;
LoginBloc() : super(const LoginState(false)) {
on<LoginEvent>(_checkLogin);
disposeEffect = effect(() {
var user = auth.currentUser.value.value;
add(LoginEvent(user));
});
}
@override
Future<void> close() async {
disposeEffect?.call();
return super.close();
}
_checkLogin(LoginEvent event, Emitter<LoginState> emit) async {
if (event.user != null) {
emit(const LoginState(true));
} else {
emit(const LoginState(false));
}
}
}

When the LoginBloc it’s created it will start listening for the value in the currentUser stream of the Auth instance. It will inject a new event directly into the bloc so we can later emit the matching LoginState.

Listen to LoginState changes

Now that we have our bloc in place, you only need to use it in the root of your application:

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Super App',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.yellow),
useMaterial3: true,
extensions: const <ThemeExtension<dynamic>>[
LoginThemeExtension(
backgroundImage: "assets/images/pexels-20367724.jpg",
),
],
),
home: MultiBlocProvider(
providers: [
BlocProvider(
create: (BuildContext context) => LoginBloc(),
)
],
child: BlocBuilder<LoginBloc, LoginState>(
builder: (BuildContext context, LoginState state) {
if (state.isLoggedIn) {
return ToDoScreen();
} else {
return LoginScreen();
}
},
),
),
);
}

Now, the root of the app will change if the user is logged in or not and we will show the right app state to the user.

If you have more bloc providers, just add them to the MultiBlocProvider.