Most of the time, it's required for you to check if the user's identifier (their email or phone number) is valid. With Cotter, you can verify your users via email, SMS, or WhatsApp.
Step 1: Set Up Deep Linking
The verification will follow OAuth's PKCE flow which will open an in-app browser where your user can enter the OTP sent to their email/phone.
Pick a unique URL scheme for redirecting the user back to your app after the verification in the in-app browser is successful. For this example, we'll use myexample://auth_callback .
Setup in iOS
Add the following to your ios/Runner/Info.plist.
ios/Runner/Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- ADD THE LINES FROM HERE -->
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>myexample</string> <!-- 👈 Change this to your own URL Scheme -->
<key>CFBundleURLSchemes</key>
<array>
<string>myexample</string> <!-- 👈 Change this to your own URL Scheme -->
</array>
</dict>
</array>
<!-- TO HERE -->
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
Setup in Android
Add the following to your android/app/src/main/AndroidManifest.xml.
android/app/src/main/AndroidManifest.xml
<manifest ...>
<application ...>
...
<!-- Add the lines from here -->
<activity android:name=".CallbackActivity" >
<intent-filter android:label="flutter_web_auth">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- 👇 This is for myexample://auth_callback -->
<data android:scheme="myexample" android:host="auth_callback"/>
</intent-filter>
</activity>
<!-- Until here -->
</application>
</manifest>
You may need to stop flutter-run and re-run it to see the changes.
The user will be asked to verify their email or phone number
If verification successful, we'll create a new User
Then, set up the current device as trusted.
// 2️⃣ Make Sign Up FunctionvoidsignUp(BuildContext context) async {try {// ❌ Remove this linevar user =await cotter.signUpWithDevice(identifier: inputController.text);// ✅ Add the lines from here// (1) Verify the user's email// (2) Create the user if verification successfulvar user =await cotter.signUpWithEmailOTP( redirectURL:"myexample://auth_callback", email: inputController.text, );// (3) Set up the current device as trusted user =await user.registerDevice();// To here } catch (e) {print(e); } }
// 2️⃣ Make Sign Up FunctionvoidsignUp(BuildContext context) async {try {// ❌ Remove this linevar user =await cotter.signUpWithDevice(identifier: inputController.text);// ✅ Add the lines from here// (1) Verify the user's phone// (2) Create the user if verification successfulvar user =await cotter.signUpWithPhoneOTP( redirectURL:"myexample://auth_callback", channels: [PhoneChannel.SMS, PhoneChannel.WHATSAPP], // optional, default is SMS );// (3) Set up the current device as trusted user =await user.registerDevice();// To here } catch (e) {print(e); }}
// 2️⃣ Make Sign Up FunctionvoidsignUp(BuildContext context) async {try {// ❌ Remove this linevar user =await cotter.signUpWithDevice(identifier: inputController.text);// ✅ Add the lines from here// (1) Verify the user's phone// (2) Create the user if verification successfulvar user =await cotter.signInWithPhoneOTPViaSMS( redirectURL:"myexample://auth_callback", phone: inputController.text, );// (3) Set up the current device as trusted user =await user.registerDevice();// To here } catch (e) {print(e); }}
// 2️⃣ Make Sign Up FunctionvoidsignUp(BuildContext context) async {try {// ❌ Remove this linevar user =await cotter.signUpWithDevice(identifier: inputController.text);// ✅ Add the lines from here// (1) Verify the user's phone// (2) Create the user if verification successfulvar user =await cotter.signInWithPhoneOTPViaWhatsApp( redirectURL:"myexample://auth_callback", phone: inputController.text, );// (3) Set up the current device as trusted user =await user.registerDevice();// To here } catch (e) {print(e); }}
Option 2: Verifying After Registering the User
This will work the following way:
The user will enter some identifier (email or phone number), and we'll create a new User with that unverified identifier.
Set up the current device as trusted.
Once the user is logged-in, ask the user to verify their email/phone number
// 2️⃣ Make Sign Up FunctionvoidsignUp(BuildContext context) async {try {var user =await cotter.signUpWithDevice(identifier: inputController.text);// ✅ Add the line below// (3) Verify the user's email user =await user.verifyEmailWithOTP(redirectURL:"myexample://auth_callback"); } catch (e) {print(e); }}
// 2️⃣ Make Sign Up FunctionvoidsignUp(BuildContext context) async {try {var user =await cotter.signUpWithDevice(identifier: inputController.text);// ✅ Add the line below// (3) Verify the user's phone user =await user.verifyPhoneWithOTPViaSMS(redirectURL:"myexample://auth_callback"); } catch (e) {print(e); }}
// 2️⃣ Make Sign Up FunctionvoidsignUp(BuildContext context) async {try {var user =await cotter.signUpWithDevice(identifier: inputController.text);// ✅ Add the line below// (3) Verify the user's phone user =await user.verifyPhoneWithOTPViaWhatsApp(redirectURL:"myexample://auth_callback"); } catch (e) {print(e); }}
Make sure that the identifier that you used inside cotter.signUpWithDevice has the correct type. (If the identifier is an email, then use verifyEmailWithOTP, and so on).
🎉 You're done!
You should now be able to enter your email or phone number during the signup process.