Build Custom Authentication Using Appsmith and APISIX

Bobur Umurzokov - Jun 6 '23 - - Dev Community

Authentication flow is a fundamental part of web applications. It ensures the security and privacy of user data while they are using your app. While there are many off-the-shelf authentication solutions available, building an authentication system using a low-code UI development platform and API management solution allows you to create secure web applications with ease. You can create an application without having knowledge of both frontend and backend technologies and tools. You do not need to know Python, Java, HTML, CSS, or other JavaScript frameworks. In this post, you’ll learn how to build a custom simple login flow and pages on UI to secure your application using Appsmith, Apache APISIX, and JWT.

Appsmith is a powerful low-code development platform that enables users to easily create web applications and dashboards. It provides a visual interface and a comprehensive set of pre-built components, making it accessible to developers and non-developers.

Learning objectives

You will learn the following throughout the article:

  • Design an authentication process in low-code environment.
  • Set up the backend authentication API with APISIX.
  • Create UI Pages using widgets in Appsmith.
  • Enable token-based authentication.

Design the Authentication Architecture

Before diving into implementation, it is important to first design the architecture of your authentication system for your application. Consider the key components such as user registration, login, password, session management, and JWT token-based authentication. Define the flow of information between Appsmith and APISIX, ensuring a clear and efficient authentication workflow.

Build Custom Authentication Using Appsmith and APISIX.png

We are going to build a simple mobile app that has 3 pages Registration, Login, and Main pages respectively. Tasks we do divide into two parts. In the first part, We will set up the backend API with Apache APISIX API Gateway that will handle authentication requests. We use existing API Gateway endpoints to achieve user registration, login, and token generation flows. In the second part, we use Appsmith’s drag-and-drop interface with ready UI components to build the Registration, Login, and Main pages and finally, we connect them to API to handle form submissions. Let’s start with building these components in the following sections.

Registration, Login, and Main

Part 1: Set Up the backend authentication API

We start by setting up the backend API that will handle authentication requests from the mobile app. APISIX can be utilized to enforce authentication to protect API endpoints. APISIX allows you to validate user credentials, issue authentication tokens, and control access to your APIs. By integrating APISIX into your mobile authentication system, you can add an additional layer of security and ensure that only authenticated users can access your protected resources.

Prerequisites

  • Docker is used to installing the containerized etcd and APISIX.
  • curl is used to send requests to APISIX Admin API. You can also use tools such as Postman to interact with the API.

Step 1: Install Apache APISIX

APISIX can be easily installed and started with the following quickstart script:

curl -sL https://run.api7.ai/apisix/quickstart | sh
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure the backend service (upstream)

Next, we configure our backend service. For demo purposes, it can be any API service that serves our backend logic. You can replace it with your service too. I use a mock public server http://httpbin.org/ that randomly generates responses. For simplicity, we will have a single endpoint that returns the public IP address of our machine in this endpoint http://httpbin.org/ip.

To route requests to the backend service for the mock API, you'll need to configure it by adding an upstream server in Apache APISIX via the Admin API.

curl http://127.0.0.1:9180/apisix/admin/upstreams/1 -X PUT -d '
{
   "name":"Mock API upstream",
   "desc":"Register Mock API as the upstream",
   "nodes":{
      "httpbin.org:80":1
   }
}'
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a new plugin config

This step involves configuring a plugin (using the Plugin Config object) for a route we create in the next step. So, APISIX enables the JWT plugin to secure our endpoints. Each time we request the endpoint, it checks JWT credentials in the request header.

curl http://127.0.0.1:9180/apisix/admin/plugin_configs/1 -X PUT -d ' 
{
   "plugins":{
      "jwt-auth": {}
   }
}'
Enter fullscreen mode Exit fullscreen mode

Step 4: Create a Route for the backend API

We create a new Route object in APISIX that intercepts all GET requests to /ip URI, and uses the existing upstream and plugin configurations to enable the routing mechanism and authentication policies. It checks for the JWT plugin in the header, and if it exists and valid, forwards the request to our mock server. Otherwise, it returns an unauthorized error immediately and the request will not reach the actual service.

curl -i http://127.0.0.1:9180/apisix/admin/routes/1 -X PUT -d '
{
   "name":"Mock API server route",
   "desc":"Create a new route in APISIX for the mock server endpoint",
   "methods":[
      "GET"
   ],
   "uri":"/ip",
   "upstream_id":"1",
   "plugin_config_id":1
}'
Enter fullscreen mode Exit fullscreen mode

Step 5: Create a Route for signing the JWT token

We implemented token-based authentication for our API. APISIX can also act as an identity provider to generate and validate tokens. To do so, you need to set up a Route for a new API endpoint that signs the token using the public-api plugin:

curl http://127.0.0.1:9180/apisix/admin/routes/login -X PUT -d '
{
    "uri": "/login",
    "plugins": {
        "public-api": {
            "uri": "/apisix/plugin/jwt/sign"
        }
    }
}'
Enter fullscreen mode Exit fullscreen mode

By executing the above curl command, we registered a new route called login with the URI path /login that signs a new token whenever an existing user attempts to log in from the Login page on the mobile app using their emails.

Part 2: Create User Registration and Login Forms in Appsmith

Using Appsmith's low-code interface, we can create user registration and login forms. Appsmith provides a wide range of pre-built widgets that can be easily customized. Design the forms with input fields for username, password, and any additional information you require in the dashboard.

Before you begin

I am going to miss the installation part of Appsmith on your machine. You can learn how to install Appsmith using Docker on the Appsmith website. Make sure that you installed Appsmith and you can access it at http://localhost. When you deploy and run Appsmith, an application titled My first application is added by default. You can use this application to build your first app.

My first application Appsmith

Step 1: Create a Registration page

In our case, a new user first registers on a mobile app from the Registration page. Start by creating a new page called RegistrationPage in your application. Add Input widgets for email (named EmailInput), username (named UsernameInput), and password (PasswordInput). Also, add Register(named RegisterButton) and Login (named LoginButton) Button widgets to the drawing board. The final result looks like below:

RegistrationPage

When a user presses the Register button with provided input details, you'll need a query to handle communication with the APISIX Admin API endpoint to register a new API consumer in the API Gateway. Create an API query (named APISIX_Admin_Add_Consumer_API) with APISIX consumers endpoint URI /apisix/admin/consumers. Place the Input widgets text into your query body. Accessing the Input widgets should look something like this:

API query for JWT token

Note that we use the address of host.docker.internal instead of localhost because APISIX is running inside its own container on a different docker network than Appsmith.

After the query is sent to APISIX, it registers the new consumer, and the consumer object will use jwt-authplugin with key and secret. You can test if the consumer is registered in the system successfully but fetching the specified consumer by username appsmithuser. Run this curl command:

curl http://127.0.0.1:9180/apisix/admin/consumers/appsmithuser
Enter fullscreen mode Exit fullscreen mode

While existing users can go directly to the Login page. See in the next section.

Step 2: Create a Login page

Back on the application canvas, add a new page called Login page and set up the Login form's with Input (for entering the user’s email) and Button (for login) widgets.

Login page

Then create an API query (named login_api) for for APISIX login route URI path /login and set key param to {{EmailInput.text}}. If you test the query and push the run button, on a successful response, our authentication API Gateway endpoint should return a valid access token. In the example below, the jwt key is a token that indicates that the user has been authenticated on the APISIX side.

Rest call to login endpoint

To run the login_api query via the Login button, you need to set the query onClick property.

login_api

It is also possible to store the JWT token in the Appsmith store and then take the user to the MainPage. To do so, insert the below code to the login_api action of Login page in the onClick property:

{{login_api.run(() => {
  const jwt = login_api?.data;
  if (jwt) {
    storeValue('jwt', jwt);
    navigateTo('MainPage', {});
  } else {
    showAlert('Login failed!', 'error');
  }
})}}
Enter fullscreen mode Exit fullscreen mode

login_api on click

If the user fails to authenticate with APISIX, show an alert message as a callback to tell the user that there was an error.

Step 3: Create a Main page

Finally, now, it's time to configure the MainPage of the mobile app to allow access to logged-in users and show some data. You can use the same canvas to build your UI from widgets. Once the user successfully logged in, our logic navigates to MainPage, and on the first-page load, it makes an API call automatically to the route http://127.0.0.1:9080/ip in APISIX using the query you add (named main_page_data_api) and retrieves the IP address from the upstream server (we created in Part 1 and at step 2).

main_page_data_api

You may notice in the Authorization header the value {{appsmith.store.jwt}} the jwt value that we saved in the Appsmith store in the previous step which is used to prove to your application that the user is recognized. If the jwt value does not exist in the Appsmith store, we show an unauthorized error to the user.

In my case, I added two Text widgets to the MainPage and set the text field value of the second to {{main_page_data_api.data}} which is simply output data from main_page_data_apicall. See the result.

Main page

Next steps

You can also add one Unauthorized page for redirecting unauthorized users to that page, show the error and suggest they log in or register to create a new account. Provide your users with the ability to log out of your app with a button widget when they're finished which can help increase the security of your data.

Conclusion

By following the above steps, we created the personalized authentication system using Appsmith and APISIX. Appsmith is suitable for a wide range of use cases, from building internal tools and admin dashboards to prototyping and developing full-fledged applications. With APISIX, you can not only enforce authentication for your users but also introduce additional security measures such as rate limiting, IP blocking, and consumer restriction to maintain the security of our custom authentication solution.

Related resources

Community

🙋 Join the Apache APISIX Community

🐦 Follow us on Twitter

📝 Find us on Slack

💁 How to contribute page

About the author

Follow me on Twitter: @BoburUmurzokov

Visit my blog: www.iambobur.com

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .