Flutter Passwordless Authentication
Table of contents
- Setting up Magic URL Authentication in Flutter with Appwrite
- Step 1: Create or Use an Existing Flutter Project
- Step 2: Android Configuration
- Step 3: iOS Configuration
- Step 3: iOS Configuration
- Step 4: Set Up an Appwrite Project
- Step 5: Add Appwrite SDK to Flutter
- Step 6: Initialize Appwrite in Your Flutter App
- Step 7: Create the Login Screen with Magic URL
- Step 8: Handle the Magic URL Callback
- Step 9: Authenticate the User
- 🔐 Login with a Magic URL
What is Appwrite ?
Appwrite is an end-to-end backend service aiming to simplify web and mobile app development similar to Firebase. As an open-source alternative, Appwrite allows hosting the backend yourself instead of relying on a vendor-controlled platform.
Some key aspects of Appwrite:
Combines NoSQL, SQL databases to balance flexibility and structure.
Includes user management, multi-factor authentication, OAuth integrations, and email-sending capability.
- File storage system handles security, compression, virus scanning, and media metadata extraction.
- Customizable and extensible architecture allows modifying the codebase to meet specific needs.
Setting up Magic URL Authentication in Flutter with Appwrite
Step 1: Create or Use an Existing Flutter Project
In this tutorial we will learn how we can use Magic URL Authentication in our Flutter applications using Appwrite's Flutter SDK.
The same can be done with our Web SDK and Android SDK. As this feature needs to send an email, you must properly setup SMTP service in Appwrite.
flutter create magic_auth_flutter
cd magic_auth_flutter
Step 2: Android Configuration
To configure Android deep linking, open AndroidManifest.xml
and add the following under <activity android:name= ".MainActivity">
:
<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="appwrite-callback-auth-[PROJECT_ID]" android:host="magicurl_session" />
</intent-filter>
Replace [PROJECT_ID]
with your Appwrite project ID.
Step 3: iOS Configuration
Step 3: iOS Configuration
For iOS, open Info.plist
and add the following:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleURLSchemes</key>
<array>
<string>appwrite-callback-auth-[PROJECT_ID]</string>
</array>
</dict>
</array>
<key>FlutterDeepLinkingEnabled</key>
<true/>
Again, replace [PROJECT_ID]
with your actual project ID.
Step 4: Set Up an Appwrite Project
Go to Appwrite Cloud or use your self-hosted Appwrite setup. After logging in, create a new project and enable Magic URL authentication from the authentication settings.
Add the necessary platforms (iOS, Android, and Web) and configure the redirect domains.
Step 5: Add Appwrite SDK to Flutter
In your Flutter project, add the Appwrite SDK by running:
flutter pub add appwrite
This will include the latest version of Appwrite in your pubspec.yaml
. Ensure the Appwrite version aligns with your server setup if you're using self-hosted Appwrite.
Step 6: Initialize Appwrite in Your Flutter App
In your Flutter app, initialize the Appwrite client. For better structure, create a separate file [appwrite_client.dart
] for this:
import 'package:appwrite/appwrite.dart';
Client client = Client();
void initAppwrite() {
client
.setEndpoint('https://cloud.appwrite.io/v1') // Your Appwrite API Endpoint
.setProject('auth-labs'); // Replace with your project ID
}
Call this initialization in your main.dart
:
void main() {
WidgetsFlutterBinding.ensureInitialized();
initAppwrite();
runApp(MyApp());
}
Step 7: Create the Login Screen with Magic URL
We’ll now implement a simple login screen where users enter their email to receive a Magic URL:
class LoginScreen extends StatelessWidget {
final _emailController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () => _sendMagicURL(_emailController.text),
child: Text('Login'),
),
],
),
),
);
}
Future<void> _sendMagicURL(String email) async {
final account = Account(client);
try {
await account.createMagicURLSession(
email: email,
url: 'appwrite-callback-auth-[PROJECT_ID]://magicurl_session',
);
// Handle success (e.g., show notification)
} on AppwriteException catch (e) {
print('Error: ${e.message}');
}
}
}
Replace [PROJECT_ID]
with your project’s ID and configure the correct URL.
Step 8: Handle the Magic URL Callback
Once the user clicks the Magic URL, Appwrite will redirect them to your app with a user ID and a secret in the query parameters. Set up a route to handle this:
final router = GoRouter(
routes: [
GoRoute(
path: '/magicurl_session',
builder: (context, state) {
final userId = state.queryParams['userId']!;
final secret = state.queryParams['secret']!;
return MagicUrlSessionPage(userId: userId, secret: secret);
},
),
],
);
Step 9: Authenticate the User
Create the MagicUrlSessionPage
to complete the authentication:
class MagicUrlSessionPage extends StatelessWidget {
final String userId;
final String secret;
MagicUrlSessionPage({required this.userId, required this.secret});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Authenticating...')),
body: FutureBuilder(
future: _authenticateUser(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
return Center(child: Text('Authenticated successfully!'));
}
},
),
);
}
Future<void> _authenticateUser() async {
final account = Account(client);
try {
await account.updateMagicURLSession(userId: userId, secret: secret);
} on AppwriteException catch (e) {
throw Exception('Authentication failed: ${e.message}');
}
}
}
🔐 Login with a Magic URL
If you do want to handle the completion of magic URL session and redirection yourself, you need to build a web app that can handle the process. And you need to pass the URL of this web app in the URL parameter while calling createMagicURLSession
.
Use the updateMagicURLSession()
method and call it with the secret and userId values from the URL's query string.
const urlParams = new URLSearchParams(window.location.search);
const userId = urlParams.get('userId');
const secret = urlParams.get('secret');
let promise = appwrite.account.updateMagicURLSession(userId, secret);
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
If the updateMagicURLSession()
succeeded, the user is now logged in.
Note that, Once clicked magic link is null and void.
Conclusion
With Appwrite’s Magic URL authentication, user can implemented a secure, passwordless login mechanism in Flutter. This setup improves user experience while enhancing security by avoiding password-based vulnerabilities. You can now integrate this flow into your apps and provide your users with a quick and secure login experience.
Subscribe to my newsletter
Read articles from Pratiksha kadam directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by