Implementing User Login in Your Web Application

In this article, we will discuss how to securely implement user login in your web application, specifically:

  • How to securely store your user’s passwords in the database
  • How to implement login with external providers such as Google, Microsoft, Facebook
  • How to take advantage of 2-factor authentication for added security.

Pre-requisites

You’d need to install the Integration Library package using the LANSA Package Manager.
See this usage guide for how to use the LANSA Package Manager.

Running the Sample Application

In the Package Manager, go to the Samples tab, and click on the Login Form sample.

You should see the following webpage on your default browser:

Storing Passwords Securely in the Database

For security reasons, you should store just the cryptographic hash of the user’s passwords in the database. The hash is generated using a one-way hash function (that is, given the hash, it’s very difficult to compute the original password). Each user should also have a cryptographic key associated with them (every user should have a different key). This key should be used when hashing the password, which makes brute force attack using well-known passwords much harder as every user will have different password hash, even if they have the same password. The user’s cryptographic key should be generated using a cryptographically secure random number generator.

A user’s cryptographic key is created during the user registration process. Use the XUserAccount_Crypto (from the Integration Library package) to generate the key for you. The XUserAccount_Crypto provides common cryptographic functionality for user security.

* Create an instance of the XUserAccount_Crypto class
Define_Com Class(#XUserAccount_Crypto) Name(#UserCrypto)

* Generate a random cryptographic key
#UserCrypto.GenerateUserCryptoKey

* Assign the generated key to a field so we can insert it to the user database table
* We need to store the key alongside the password in the database, as we need to use it
* when verifying the password during login process
#FieldCryptoKey := #UserCrypto.UserCryptoKey.AsNativeString

* You then proceed to generate the user's password hash, using the ComputePasswordHash function.
#FieldPasswordHash := #UserCrypto.ComputePasswordHash( #Password )

* Create a new row in the user table to represent the new user …
* … insert the #FieldCryptoKey and #FieldPasswordHash fields
Insert Fields(. . .) To_File(UserTable)

To validate the password, use the ValidatePassword method. You’d need to read the user’s cryptographic key from the database, and assign that to the instance of the XUserAccount_Crypto you are using:

* Read password & cryptographic key from the database
* Put in #FieldPasswordHash and #FieldCryptoKey fields
* Assign crypto key to the #UserCrypto object
#UserCrypto.UserCryptoKey := #FieldCryptoKey

* Validate the password the user entered during the login process (#EnteredPassword) ...
* ... against the hash in the database (#FieldPasswordHash)
#UserCrypto.ValidatePassword Password(#EnteredPassword) PasswordHash(#FieldPasswordHash) OK(#OK)

Implementing 2-Factor Authentication (2FA) Using One-time Token


The algorithm that we are using to generate the token is time-based one-time password (TOTP). In short, the generator is a function that takes two parameters: a cryptographic key, and the current time. The generated token is valid for the duration of the time-window (e.g. 30 seconds, or1 minute). Generally speaking, the advantage of TOTP is that it can be generated independently by a client, even without Internet connection (as long as the time on the client matches the server). Validation is also simple as we just need to re-generate the token using the two parameters (key and time), and see if it matches the token entered by the user (the actual implementation is a bit more complicated than this, but unless you are going to implement your own generation/validation, it’s good enough)

Note that in this article, since we are use email/SMS to send the token, strictly speaking we don’t really need to use TOTP algorithm (we can just generate a random token and record it in the database), but since TOTP is very simple to implement, there is no reason not to use it.

The Integration Library provides an easy way to generate and SMS or email a token. Note that the token generation also requires the user’s cryptographic key, so make sure that you have generated/assigned the key to the instance of XUserAccount_Crypto you are using.

Configuring Security Token Properties (2FA)

You can configure the length and validity window size of the token. Open the Integration Library configuration tool (from the Package Manager) and navigate to One Time Token >> General

Signing-in with third-party identity providers (Google, Microsoft, Facebook)


To enable support for signing-in using third-party providers, you will need to register and configure each provider individually.

Signing-in with third-party providers uses a protocol called OAuth2.
Have a look at this guide for a brief introduction to OAuth2.