# Supabase Deep Linking with Redirectly > Integrate Redirectly with Supabase for email verification and magic link flows in Flutter. Handle auth deep links and verify users on first app launch. - Canonical: https://redirectly.app/integrations/supabase - Site: [Redirectly](https://redirectly.app) — deferred deep linking for Flutter & React Native Complete guide to implementing email verification and magic link flows in Flutter. Learn how to handle authentication deep links and verify users when they launch your app. ## Supabase + Redirectly for auth flows Supabase provides excellent authentication infrastructure, and Redirectly enables deferred deep linking for authentication flows. When users click email verification or magic link emails, Redirectly ensures they reach the right screen even if your app isn't installed yet. ### The challenge - User receives email verification link from Supabase - If they haven't installed your app yet, the link doesn't work - Manual copy-paste of tokens is frustrating and error-prone - Users abandon signup or email verification flows ### The solution 1. Generate Redirectly links in your Supabase auth hooks 2. Include verification token in deep link parameters 3. User clicks link, installs app if needed, and is auto-verified 4. Seamless onboarding experience ## Email verification flow implementation Set up email verification using Supabase and Redirectly together. This example shows how to generate verification links that work before app installation. ```dart // lib/services/supabase_auth_service.dart import 'package:supabase_flutter/supabase_flutter.dart' import 'package:redirectly/redirectly.dart' import 'package:http/http.dart' as http class SupabaseAuthService { final supabase = Supabase.instance.client Future signUpWithEmail( String email, String password, ) async { try { // Sign up with Supabase await supabase.auth.signUp( email: email, password: password, ) // Generate Redirectly deep link for verification final deepLink = await _generateVerificationLink(email) // Send custom email with Redirectly link // (Or configure Supabase auth emails to use your domain) await _sendVerificationEmail(email, deepLink) } catch (e) { print('Sign up error: $e') } } Future _generateVerificationLink(String email) async { final session = supabase.auth.currentSession final token = session?.user.id ?? '' // Create Redirectly deep link with verification token final redirectlyUrl = Uri.https( 'api.redirectly.app', '/link/create', { 'apiKey': 'your_api_key', 'path': 'verify-email', 'query': 'token=$token&email=$email', 'subdomain': 'myapp', }, ) final response = await http.post( redirectlyUrl, headers: {'Content-Type': 'application/json'}, ) if (response.statusCode == 200) { final json = jsonDecode(response.body) return json['link'] as String } throw Exception('Failed to create link') } Future _sendVerificationEmail( String email, String deepLink, ) async { // Use your email service to send verification email // Include the Redirectly link print('Send verification email to $email with link: $deepLink') } } ``` The key insight: include the verification token as a query parameter in the Redirectly deep link. When your app launches, retrieve this token and confirm it with Supabase. ## Verify emails when app launches In your app's main widget, listen for deep link events and handle email verification automatically. ```dart // lib/main.dart import 'package:flutter/material.dart' import 'package:redirectly/redirectly.dart' import 'services/supabase_auth_service.dart' void main() async { WidgetsFlutterBinding.ensureInitialized() await Redirectly.initialize( apiKey: 'your_api_key', ) runApp(const MyApp()) } class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key) @override State createState() => _MyAppState() } class _MyAppState extends State { final authService = SupabaseAuthService() @override void initState() { super.initState() _setupDeepLinkListener() } void _setupDeepLinkListener() { // Listen to deep links from Redirectly Redirectly.onDeepLink.listen((link) { print('Deep link received: ${link.path}') print('Query params: ${link.params}') // Handle email verification flow if (link.path == 'verify-email') { final token = link.params['token'] as String? final email = link.params['email'] as String? if (token != null && email != null) { _handleEmailVerification(token, email) } } }) } Future _handleEmailVerification( String token, String email, ) async { try { // Verify with Supabase using the token final response = await authService .supabase .auth .verifyOTP( email: email, type: OtpType.email, token: token, ) if (response.session != null) { // User is verified, navigate to main app Navigator.of(context).pushReplacementNamed('/home') ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Email verified!')), ) } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Verification failed: $e')), ) } } @override Widget build(BuildContext context) { return MaterialApp( title: 'MyApp', home: const AuthScreen(), ) } } ``` ## Passwordless auth with magic links Supabase also supports passwordless sign-in with magic links. Use the same Redirectly integration for an even smoother experience. ```dart // Magic link sign-in with Redirectly deep linking Future signInWithMagicLink(String email) async { try { // Generate Redirectly deep link for magic link flow final deepLink = await _generateMagicLinkDeepLink(email) // Sign in with Supabase magic link await supabase.auth.signInWithOtp( email: email, emailRedirectTo: deepLink, // Use Redirectly link ) ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Check your email for the Redirectly deep link', ), ), ) } catch (e) { print('Magic link error: $e') } } // Redirectly link for magic link flow Future _generateMagicLinkDeepLink(String email) async { final response = await http.post( Uri.https('api.redirectly.app', '/link/create'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({ 'apiKey': 'your_api_key', 'path': 'magic-link-signin', 'query': 'email=$email', 'subdomain': 'myapp', }), ) if (response.statusCode == 200) { return jsonDecode(response.body)['link'] } throw Exception('Failed to create magic link') } ``` ## Key considerations for secure auth flows ### Token expiration Set reasonable expiration times on verification tokens. Supabase automatically expires OTP tokens after 15 minutes by default. Consider the time it takes for app installation. ### Secure link generation Always generate Redirectly links server-side using your API key. Never expose tokens in client-side code. Use HTTPS for all link generation and token transmission. ### Redirect URL validation Validate that deep link parameters match your expected schema before processing authentication. Prevent malicious actors from injecting false verification data. ### Fallback handling Provide a fallback mechanism for users who don't have your app installed. Include a web-based verification page as a backup option. ## Next steps Combine Supabase auth with Redirectly deferred deep linking: - [Flutter Deferred Deep Linking](https://redirectly.app/flutter-deferred-deep-linking.md) - [Email Verification Deep Linking](https://redirectly.app/blog/email-verification-deep-linking.md) - [All Integrations](https://redirectly.app/integrations.md) - [React Native Deep Linking](https://redirectly.app/react-native-deferred-deep-linking.md) --- Full site index for AI agents: https://redirectly.app/llms.txt