Email/SMS Authentication

Register or login a user using One-Time Passcodes or Magic Links on Android

Your Passage app will default to One-Time Passcodes, but you can also choose to use Magic Links instead. Both One-Time Passcodes and Magic Links can be sent via email or phone (depending on what kind of identifier your user provides).

Passage highly recommends using One-Time Passcodes over Magic Links, as they are easier to implement, more secure, and a better user experience.

One-Time Passcode (OTP)

Register with OTP

Here's an example of how to register a user using OTPs.

Send a new registration OTP to user

Call passage.newRegisterOneTimePasscode to send your user a new passcode for registration. A successful call will return a OTP id, which you'll need to finish user registration later.

suspend fun sendRegistrationOTP(identifier: String) {
    try {
        val otpId = passage.newRegisterOneTimePasscode(identifier).otpId
	// Returns an OTP id which you'll need later for completing user registration.
    } catch (e: NewRegisterOneTimePasscodeException) {
        when (e) {
            is NewRegisterOneTimePasscodeInvalidIdentifierException -> {
                // Alert user their email or phone number was invalid
            }
        }
    }
}

Activate registration OTP

When the user inputs their OTP into your app, you'll send their input string along with the OTP id through passage.oneTimePasscodeActivate.

suspend fun authenticateOTPUser(otp: String, otpId: String) {
    try {
	// Where "otp" is the code the user input and "otpId" is from passage.newRegisterOneTimePasscode
        passage.oneTimePasscodeActivate(otp, otpId)
        // Do authenticated stuff
    } catch (e: OneTimePasscodeActivateException) {
        when (e) {
            is OneTimePasscodeActivateInvalidRequestException -> {
                // Alert user their passcode was invalid
            }
        }
    }
}

For the best user experience, we recommend implementing the SMS Retriever API for users that authenticate with a phone number. This enables the user to tap a button to fill out the code input, rather than requiring them to type each number.

Log in with OTP

Here's an example of how to log in a user using OTPs.

Send a new login OTP to user

Call passage.newLoginOneTimePasscode to send your user a new passcode for logging in. A successful call will return a OTP id, which you'll need to finish user login later.

suspend fun sendLoginOTP(identifier: String) {
    try {
        val otpId = passage.newLoginOneTimePasscode(identifier).otpId
        // Returns an OTP id which you'll need later for completing user login.
    } catch (e: NewLoginOneTimePasscodeException) {
        when (e) {
            is NewLoginOneTimePasscodeInvalidIdentifierException -> {
                // Alert user their email or phone number was invalid
            }
        }
    }
}

Activate login OTP

The method for activating a login OTP is the same as activating a registration OTP. See above example.

Here's an example of how to register a user using Magic Links.

Call passage.newRegisterMagicLink to send your user a new Magic Link for registration. A successful call will return a Magic Link id, which you'll need to finish user registration later.

suspend fun sendRegistrationMagicLink(identifier: String) {
    try {
        val magicLinkId = passage.newRegisterMagicLink(identifier).id
	// Returns a Magic Link id which you'll need later to check the status of the magic link.
    } catch (e: NewRegisterMagicLinkException) {
        when (e){
            is NewRegisterMagicLinkInvalidIdentifierException -> {
                // Alert user their email or phone number was invalid
            }
        }
    }
}

If the user opens the Magic Link from the same Android device and you’ve setup App Linking correctly, that link will open your Android app and you can grab the magic link string from your Activity’s onNewIntentmethod (see example here). Then you can call passage.magicLinkActivate(userMagicLink) to authenticate the user.

suspend fun authenticateMagicLinkUser(userMagicLink: String) {
    try {
        passage.magicLinkActivate(userMagicLink) ?: return
        // Do authenticated stuff
    } catch (e: MagicLinkActivateException) {
        when (e) {
            is MagicLinkActivateInvalidException -> {
                // Alert user that the magic link is no longer valid
            }
        }
    }
}

If the user opens the Magic Link on a different device or you have not setup App Linking, it is up to your web front end to handle and activate the Magic Link. In this case, you’ll need to continually check the status of the link in your Android app. Once the Magic Link has been activated by the web front end, passage.getMagicLinkStatus will return a PassageAuthResult and your user will be authenticated.

suspend fun checkMagicLinkStatus(magicLinkId: String) {
    try {
	// Where "magicLinkId" is from passage.newRegisterMagicLink
        passage.getMagicLinkStatus(magicLinkId) ?: return
        // Do authenticated stuff
    } catch (e: GetMagicLinkStatusException) {
        when (e) {
            is GetMagicLinkStatusInvalidException -> {
		// Alert user that the magic link is no longer valid
	    }
        }
    }
}

Here's an example of how to log in a user using Magic Links.

Call passage.newLoginMagicLink to send your user a new passcode for logging in. A successful call will return a Magic Link id, which you'll need to finish user login later.

suspend fun sendLoginMagicLink(identifier: String) {
    try {
        val magicLinkId = passage.newLoginMagicLink(identifier).id
        // Returns a Magic Link id which you'll need later to check the status of the magic link.
    } catch (e: NewLoginMagicLinkException) {
        when (e){
            is NewLoginMagicLinkInvalidIdentifierException -> {
                // Alert user their email or phone number was invalid
            }
        }
    }
}

See above Activate Magic Link and Check Magic Link status sections for instructions on next steps.

Setup App Linking

If your app uses Magic Links, you’ll likely want to setup your app with App Linking. This will direct users that click on a Magic Link in their email or messaging app on their Android device to your app, rather than to a browser.

In your app’s AndroidManifest.xml file, add this intent filter to your <activity> to enable App Linking:

//..
<activity
    android:name=".MainActivity"
    android:exported="true"
    android:launchMode="singleInstance">
    //..
    
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="http" />
        <data android:scheme="https" />
        <data android:host="@string/passage_auth_origin" />
    </intent-filter>

</activity>
//..

Then you can listen for your app being opened from the Magic Link and get the magic link string in this way:

class MainActivity: AppCompatActivity() {
    //..

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        val magicLink = intent?.data?.getQueryParameter("psg_magic_link") ?: return
        // Now you can call passage.magicLinkActivate(magicLink) where needed.
    }
}

See the Passage Android Example App for full implementation here.

Last updated