Custom Phone Validation with Descope

A year and a half ago, our company switched from a self-hosted OAuth-based identity and login service to Descope, a flexible alternative packed with all of the common features you expect an authentication service to have, plus some new features and ideas that many web apps don’t currently use.

Switching to Descope has cut down issues in the login process to virtually zero. Our company uses the magic link process as the only login method (along with biometrics for returning users). Despite a mostly older user demographic, we’ve been able to onboard thousands of users without issue. Well, almost.

To reduce onboarding friction, we don’t run 2FA against phone numbers immediately on sign up. However (and primarily due to an older demographic), typo’d phone numbers aren’t entirely uncommon, and at the moment Descope lacks phone number validation beyond a basic regex-style length check. This means that if a phone number is the correct number of digits, but any number is swapped in position, we run into issues later during validation.

Descope allows the use of HTTP connectors in their flow builder, giving the ability to make basic HTTP callouts to services, and incorporate responses. To ensure phone numbers are valid, I created a basic service to run on the Cloudflare Worker edge runtime (compatible with virtually any runtime, tested with Bun as well) to take in phone numbers and validate them using Google’s libphonenumber library.

Setup

The worker is available in the Github repository.

  1. Click the “Deploy with Cloudflare” button at the bottom of the readme
  2. Follow the Cloudflare instructions to deploy in your account (you will need to create API credentials for the CF account)
  3. Once deployed, create a new HTTP connector in Descope
  4. Set the base URL to the worker URL (no base path)
  5. Give the connector a name (like “Phone Validator”) and leave everything else as default, and create the connector
  6. In the flow, find the screen where the user inputs the phone number (called “User Information” in the default flows)
  7. Add a step after the user information screen (and before any other step that comes after it), to call the HTTP connector using a POST method
  8. Set the path to /validate
  9. Set the payload to the following: { "phoneNumber": "{{form.phone}}" }
  10. (optional) test the connector and ensure that valid and invalid phone numbers have the expected response
  11. Update the error handling to “Automatic” and set the error message to something descriptive, like “Invalid phone number”
  12. Save the connector and attach the next step in your flow

Ideally I’d like Descope to have this functionality built in, but on the other hand the fact that Descope allows for this type of functionality gives me confidence that I still have a lot of control and ability for custom features outside of what’s supported out of the box.