Implementing OTPs via USSD in your application

Whether you are requiring 2FA, or validating a phone number, or completing user registration, or seeking authorization to perform a certain action on your app, One Time Passwords have become a regular feature of the systems we use.

They serve as an extra layer of security in your application or sometimes as the default layer and I can fairly postulate that an app lacking an OTP feature eventually implements/enables it in the long run. Case in point: Piggyvest after the cowrywise saga 💀


Although OTPs can be delivered via different channels (At uLesson, we make use of voice,SMS,WhatsApp and most recently USSD as delivery channels for OTP), the default option has traditionally been SMS, and for most apps, SMS remains the only option.

But the two main problems with SMS as a channel is the unreliability of delivery and the speed at which it is delivered, and this can worsen your user experience, especially when it is tied to user registration/ on-boarding. Case in point: abeg.app having problems with OTPs on launch day. 💀



USSD as a channel solves both problems to a fair extent. It is instant, OTPs can be generated in seconds and you can be sure of its reliability to a large extent, compared to SMS were the DND directive may mess you up. The downside to this however, is that it costs twice as much to dial into a USSD session, as opposed to sending an SMS. The setup costs for the USSD code itself might be on a high side for startups and businesses alike. Regardless, it makes for a solid option as an alternative to SMS delivery in these climes.

Here's a high level overview of how we implemented OTP via USSD on the uLesson app for our users in Ghana and Nigeria.

Flow diagram showing the process flow for OTP generation via USSD

The OTP request:

The process starts from a request by the client on the app to the USSD short code which is provided by the USSD service. (Using third party providers like Africastalking is much more a preferable option for your USSD service than integrating directly with the telcos for obvious reasons like bureaucracy and discrepancies in API contracts from the different network providers.) As soon as the client request comes in, the USSD service picks up the request and forwards the details to the application backend server.

The OTP generation:

The backend server receives the request from the USSD service, in our case, through a callback url. Here we are able to retrieve the user's phone number via the request.

We need a data store to hold the value of the OTP and its generation time. We also need to make sure that phone numbers are acting as a user identifier of some sort within the application. This is important to be able to validate the inputed OTP against the generated one. In this case, phone numbers are the primary account identifier.

OTPs are normally within the range of 4 to 8 digits and usually have a validity period. To solve for the case of a user making multiple requests within the same validity period, when generating the OTP, we make a check first by searching the datastore to determine if the user identified by the phone number has an existing OTP that is valid for the period. If our search returns a result, we send back that value to the USSD service, if not, we proceed with generating an OTP with the preferred length and saving it against the user's phone number on the datastore.

OTP validation:

We can retrieve the inputed OTP from the client via a form or any interface designed for this purpose. Ideally the user's phone number should already be in your system, if not, you will need to collect this as well. The client sends the request directly to the backend, rather than the USSD service, where the OTP is then validated against the user's phone number and the stipulated expiry time.

Sample code showing OTP validation

We've explored at a high level how OTPs can be delivered via USSD. There are multiple use cases depending on what your OTP is being used for. There is also higher reliability for the delivery.

Hopefully we get to see more applications exploring this channel.

**thanks to etinosa obaseki for the edits.