Add Email/Phone Verification
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
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
<plist version="1.0">
4
<dict>
5
​
6
<!-- ADD THE LINES FROM HERE -->
7
<key>CFBundleURLTypes</key>
8
<array>
9
<dict>
10
<key>CFBundleTypeRole</key>
11
<string>Editor</string>
12
<key>CFBundleURLName</key>
13
<string>myexample</string> <!-- πŸ‘ˆ Change this to your own URL Scheme -->
14
<key>CFBundleURLSchemes</key>
15
<array>
16
<string>myexample</string> <!-- πŸ‘ˆ Change this to your own URL Scheme -->
17
</array>
18
</dict>
19
</array>
20
<!-- TO HERE -->
21
​
22
<key>CFBundleDevelopmentRegion</key>
23
<string>en</string>
Copied!
Setup in Android
Add the following to your android/app/src/main/AndroidManifest.xml.
android/app/src/main/AndroidManifest.xml
1
<manifest ...>
2
<application ...>
3
...
4
​
5
<!-- Add the lines from here -->
6
<activity android:name=".CallbackActivity" >
7
<intent-filter android:label="flutter_web_auth">
8
<action android:name="android.intent.action.VIEW" />
9
<category android:name="android.intent.category.DEFAULT" />
10
<category android:name="android.intent.category.BROWSABLE" />
11
<!-- πŸ‘‡ This is for myexample://auth_callback -->
12
<data android:scheme="myexample" android:host="auth_callback"/>
13
</intent-filter>
14
</activity>
15
<!-- Until here -->
16
​
17
</application>
18
</manifest>
Copied!
You may need to stop flutter-run and re-run it to see the changes.

Step 2: Update your Sign Up Function

Make sure you followed the guide for Sign In with Device. Update your Sign Up Function that you made on Step 2.
There are 2 ways to do this:

Option 1: Verifying Before Registering the User

This will work the following way:
  1. 1.
    The user will be asked to verify their email or phone number
  2. 2.
    If verification successful, we'll create a new User
  3. 3.
    Then, set up the current device as trusted.
Email
Phone (with Pre-built UI)
SMS
WhatsApp
1
// 2️⃣ Make Sign Up Function
2
void signUp(BuildContext context) async {
3
try {
4
// ❌ Remove this line
5
var user = await cotter.signUpWithDevice(identifier: inputController.text);
6
7
// βœ… Add the lines from here
8
// (1) Verify the user's email
9
// (2) Create the user if verification successful
10
var user = await cotter.signUpWithEmailOTP(
11
redirectURL: "myexample://auth_callback",
12
email: inputController.text,
13
);
14
// (3) Set up the current device as trusted
15
user = await user.registerDevice();
16
// To here
17
18
} catch (e) {
19
print(e);
20
}
21
}
Copied!
1
// 2️⃣ Make Sign Up Function
2
void signUp(BuildContext context) async {
3
try {
4
// ❌ Remove this line
5
var user = await cotter.signUpWithDevice(identifier: inputController.text);
6
7
// βœ… Add the lines from here
8
// (1) Verify the user's phone
9
// (2) Create the user if verification successful
10
var user = await cotter.signUpWithPhoneOTP(
11
redirectURL: "myexample://auth_callback",
12
channels: [PhoneChannel.SMS, PhoneChannel.WHATSAPP], // optional, default is SMS
13
);
14
// (3) Set up the current device as trusted
15
user = await user.registerDevice();
16
// To here
17
18
} catch (e) {
19
print(e);
20
}
21
}
Copied!
1
// 2️⃣ Make Sign Up Function
2
void signUp(BuildContext context) async {
3
try {
4
// ❌ Remove this line
5
var user = await cotter.signUpWithDevice(identifier: inputController.text);
6
7
// βœ… Add the lines from here
8
// (1) Verify the user's phone
9
// (2) Create the user if verification successful
10
var user = await cotter.signInWithPhoneOTPViaSMS(
11
redirectURL: "myexample://auth_callback",
12
phone: inputController.text,
13
);
14
// (3) Set up the current device as trusted
15
user = await user.registerDevice();
16
// To here
17
18
} catch (e) {
19
print(e);
20
}
21
}
Copied!
1
// 2️⃣ Make Sign Up Function
2
void signUp(BuildContext context) async {
3
try {
4
// ❌ Remove this line
5
var user = await cotter.signUpWithDevice(identifier: inputController.text);
6
7
// βœ… Add the lines from here
8
// (1) Verify the user's phone
9
// (2) Create the user if verification successful
10
var user = await cotter.signInWithPhoneOTPViaWhatsApp(
11
redirectURL: "myexample://auth_callback",
12
phone: inputController.text,
13
);
14
// (3) Set up the current device as trusted
15
user = await user.registerDevice();
16
// To here
17
18
} catch (e) {
19
print(e);
20
}
21
}
Copied!

Option 2: Verifying After Registering the User

This will work the following way:
  1. 1.
    The user will enter some identifier (email or phone number), and we'll create a new User with that unverified identifier.
  2. 2.
    Set up the current device as trusted.
  3. 3.
    Once the user is logged-in, ask the user to verify their email/phone number
Email
SMS
WhatsApp
1
// 2️⃣ Make Sign Up Function
2
void signUp(BuildContext context) async {
3
try {
4
var user = await cotter.signUpWithDevice(identifier: inputController.text);
5
6
// βœ… Add the line below
7
// (3) Verify the user's email
8
user = await user.verifyEmailWithOTP(redirectURL: "myexample://auth_callback");
9
10
} catch (e) {
11
print(e);
12
}
13
}
Copied!
1
// 2️⃣ Make Sign Up Function
2
void signUp(BuildContext context) async {
3
try {
4
var user = await cotter.signUpWithDevice(identifier: inputController.text);
5
6
// βœ… Add the line below
7
// (3) Verify the user's phone
8
user = await user.verifyPhoneWithOTPViaSMS(redirectURL: "myexample://auth_callback");
9
​
10
} catch (e) {
11
print(e);
12
}
13
}
Copied!
1
// 2️⃣ Make Sign Up Function
2
void signUp(BuildContext context) async {
3
try {
4
var user = await cotter.signUpWithDevice(identifier: inputController.text);
5
6
// βœ… Add the line below
7
// (3) Verify the user's phone
8
user = await user.verifyPhoneWithOTPViaWhatsApp(redirectURL: "myexample://auth_callback");
9
​
10
} catch (e) {
11
print(e);
12
}
13
}
Copied!
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.