User Authentication in Flutter #1: Passwordless

Mobterest Studio
5 min readJul 13, 2023

--

Passwordless User Authentication in Flutter

Passwordless authentication eliminates the need for traditional passwords and provides a seamless user experience.

In this article, we will explore how to integrate passwordless user authentication in Flutter, a popular cross-platform framework.

Set Up Your Flutter Project

  • Make sure you have Flutter and Dart installed on your system.
  • Set up a new Flutter project or open an existing one in your preferred IDE.

Choose an Authentication Service Provider

To implement passwordless authentication, you’ll need an authentication service provider that supports this mechanism. Some popular options include Firebase Authentication, Auth0, or Okta.

In this guide, we will use Firebase Authentication due to its ease of integration and extensive documentation.

Set Up Firebase Authentication

If you haven’t already, create a Firebase project and set up Firebase Authentication for your Flutter project. Follow the Firebase documentation for step-by-step instructions on configuring Firebase and adding the necessary dependencies to your Flutter project.

Enable Email/Link Sign-in Method

In your Firebase project settings, navigate to the Authentication section and enable the Email link sign-in method which will be found in Email/Password option. This method allows users to authenticate using their email addresses without requiring a password.

Implement the Authentication Flow

Into your Flutter app:

Collect User Email

Create a screen where users can enter their email addresses to initiate the authentication process.

  • Use the Flutter TextFormField widget to capture and validate the email input.
import 'package:flutter/material.dart';

class EmailEntryScreen extends StatefulWidget {
@override
_EmailEntryScreenState createState() => _EmailEntryScreenState();
}

class _EmailEntryScreenState extends State<EmailEntryScreen> {
final _formKey = GlobalKey<FormState>();
TextEditingController _emailController = TextEditingController();

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Enter Email'),
),
body: Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email',
),
validator: (value) {
if (value.isEmpty) {
return 'Please enter your email';
}
// You can add more validation rules if necessary
return null;
},
),
SizedBox(height: 16.0),
ElevatedButton(
onPressed: () {
if (_formKey.currentState.validate()) {
String email = _emailController.text;
sendAuthenticationLink(email);
}
},
child: Text('Send Link'),
),
],
),
),
),
);
}

void sendAuthenticationLink(String email) {
}
}

Send Authentication Link

  • Once the user enters their email address, send them an authentication link via email. You can use the Firebase Authentication API to generate a sign-in link containing a unique token.
  • You’ll need to add the following dependencies to your pubspec.yaml file:
dependencies:
flutter:
sdk: flutter
firebase_core: ^1.10.0
firebase_auth: ^3.1.0
  • Import firebase_auth package
import 'package:firebase_auth/firebase_auth.dart';
  • Create the sendAuthenticationLink()

Future<void> sendAuthenticationLink(String email) async {
try {
await _firebaseAuth.sendSignInLinkToEmail(
email: email,
actionCodeSettings: ActionCodeSettings(
url: 'your-app-url', // Replace with your app's URL
androidPackageName: 'com.yourapp.package', // Replace with your Android package name
handleCodeInApp: true,
iOSBundleId: 'com.yourapp.bundle', // Replace with your iOS bundle ID
),
);
// Link sent successfully
} catch (e) {
// Error occurred while sending the link
print('Error sending authentication link: $e');
}
}

Handle the Authentication Link

When the user receives the authentication link, they can tap on it to open your Flutter app. Implement a landing page or route that handles the link verification. Extract the token from the link and pass it to the Firebase Authentication API to complete the authentication process.

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

class AuthenticationLandingPage extends StatefulWidget {
@override
_AuthenticationLandingPageState createState() =>
_AuthenticationLandingPageState();
}

class _AuthenticationLandingPageState extends State<AuthenticationLandingPage> {
@override
void initState() {
super.initState();
handleAuthenticationLink();
}

void handleAuthenticationLink() async {
final Uri link = await FirebaseAuth.instance.getInitialLink();
if (link != null) {
if (FirebaseAuth.instance.isSignInWithEmailLink(link.toString())) {
String email = getEmailFromLink(link.toString());
// Complete the authentication process
completeAuthentication(email);
}
}
}

String getEmailFromLink(String link) {
// Regular expression pattern to extract email from the link
final RegExp emailRegex = RegExp(r"(?<=email=)[^&]+");

// Find the first match of the email pattern in the link
final Match match = emailRegex.firstMatch(link);

if (match != null) {
// Extract and return the email
return match.group(0);
} else {
// No email found in the link
return null;
}
}

void completeAuthentication(String email) async {
try {
final UserCredential userCredential =
await FirebaseAuth.instance.signInWithEmailLink(
email: email,
link: link, // Replace 'link' with the authentication link received
);

final User user = userCredential.user;

if (user != null) {
// Authentication successful
// You can perform additional actions or navigate to a new screen
print('Authentication successful. User: ${user.uid}');
} else {
// Authentication failed
print('Authentication failed.');
}
} catch (e) {
// Error occurred during authentication
print('Error completing authentication: $e');
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Authentication Landing Page'),
),
body: Center(
child: CircularProgressIndicator(),
),
);
}
}

Store User Data

After successful authentication, you may want to store user data in a database or perform additional actions. Use Firebase’s Firestore or Realtime Database to store user information securely.

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

class UserDataStorage {
final CollectionReference usersCollection =
FirebaseFirestore.instance.collection('users');

void storeUserData(User user) {
usersCollection.doc(user.uid).set({
'email': user.email,
// Additional user data fields can be stored here
});
}
}

Implement UI/UX Enhancements

Consider adding UI/UX enhancements to improve the user experience during the authentication process. For example, you can display loading indicators while sending the authentication link or show a success message upon successful authentication. Use Flutter’s widget library to design visually appealing and intuitive user interfaces.

Test and Debug

Thoroughly test the authentication flow in your Flutter app. Ensure that the email link is sent correctly, the verification process works as expected, and the user’s data is stored accurately. Use Flutter’s debugging tools and Firebase’s console logs to identify and resolve any issues that arise during testing.

Conclusion

Integrating passwordless user authentication in your Flutter app can enhance security and provide a seamless user experience. By following the steps outlined in this guide, you can leverage Firebase Authentication to implement a robust and user-friendly passwordless authentication flow. Remember to stay updated with the latest Flutter and Firebase documentation to ensure your implementation remains secure and compatible with future updates.

👏🏽 Give this story a CLAP

👉🏽 Subscribe for upcoming articles

💰 Access Free Mobile Development tutorials

🔔 Follow for more

See you on next article 👋

--

--

No responses yet