Add Authentication to Any Web Page in 10 Minutes
Tags: webdev, authentication, javascript, programming
Published: 2023-08-08 11:28:52

All web apps today need users to sign in and share their info to make their own profiles. This helps the app give them a personalized experience securely. There are **two ways** that the developers can authenticate the users – either they can create their own authentication system or they can use an [identity and access management service](https://www.authgear.com/solutions/customer-identity-and-access-management) that provides secure user registration and login capabilities with built-in login pages.

This post demonstrates how to easily add authentication to **any Javascript Single Page Application (SPA)** using [Authgear](https://www.authgear.com/).

## Why Authgear?

If you use Authgear in your apps, it's like sending the sign-in process to one main login page, similar to how Google does it for Gmail, YouTube, and others. You can easily integrate **authentication features** into your app ([Angular](https://docs.authgear.com/get-started/single-page-app/angular), [Vue](https://docs.authgear.com/get-started/single-page-app/vue), [React](https://docs.authgear.com/get-started/single-page-app/react), or any JavaScript websites). It usually involves just **a few lines of code** to enable **multiple authentication methods**, such as [social logins](https://www.authgear.com/features/social-login), [passwordless](https://www.authgear.com/features/passwordless-authentication), [biometrics logins](https://www.authgear.com/features/biometric-authentication), [one-time-password (OTP)](https://www.authgear.com/features/whatsapp-otp) with SMS/WhatsApp, and multi-factor authentication (MFA).

## How it works

When your user logs in, Authgear creates a special **ID Token** that gets sent back to your app:

1. When the user hits your "login" button or links in your client app, your app sends them to the Authgear sign-in page. You can also [customize](https://docs.authgear.com/how-to-guide/customize/branding) this page.
2. The user logs into Authgear using one of the log in options you've set up (like username/password, social media log-in, passwordless, or email magic link).
3. After the user is authenticated, your app asks for the user's ID Token.
4. Authgear then gives the user's ID Token back to your app.

![Authgear authentication flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bcyorqp056cies115rnd.png)

## Implementation Overview

The implementation of authentication for SPA apps consists of two parts. In the first part, you create an Authgear app, choose a logging method and customize the sign-in UI page(optional). The second part covers the use of [Authgear’s Web SDK](https://github.com/authgear/authgear-sdk-js) to trigger authentication flow such as log-in, and log-out.

## Part 1: Configure the Authgear

### Create an Authgear Account

The first thing you’ll need to do is create an [Authgear account](https://accounts.portal.authgear.com/signup) to get started with [Authgear’s Portal](https://portal.authgear.com/) for free. 

### Create an application in the Portal

You’ll need to create an application so you know which users can log into which apps. The Authgear application is where you will configure how you want authentication to work for the project you are developing.

- Once logged into [Authgear Portal](https://portal.authgear.com/), navigate to the "Applications" tab and click "Add Application."
- Choose an appropriate application type (Single Page Application) and provide a name for your application.

![appropriate application type in Authgear](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b45386zrjuihj5vkqh87.png)
    
- Click “Save” and skip to the next tutorial page or you can also follow the [getting started guide](https://docs.authgear.com/get-started/single-page-app/website#setup-application-in-authgear) to set up the new application.

## Configure the application

After creating the application, you'll be directed to the "Settings" tab, where you can configure the application's settings.

**Configure Authorized Redirect URIs**

An **Authorized Redirect URI** is a URL in your application where Authgear redirects the user after they have authenticated. You should set it to [http://localhost:3000](http://localhost:3000/) where our SPA is running. We will create it in part 2.

**Configure Post Logout Redirect URIs**

A **Post Logout Redirect URI** is a URL in your application that Authgear can return to after the user has been logged out of the Authgear authorization server. For the logout URL, you need to set the same address [http://localhost:3000](http://localhost:3000/).

Click "Save" and keep the **Endpoint** and **Client ID** in mind. You will need it when initializing the connection through [Authgear SDK for Web](https://github.com/authgear/authgear-sdk-js) in your SPA code.

![Example SPA App configuration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2cix1dwij9h7ggif7la6.png)

> Every application in Authgear is assigned an alphanumeric, unique client ID that your application code will use to call Authgear APIs through the SDK.

### Configure the sign-in methods

Authgear supports a wide range of authentication methods. From the “Authentication” tab, you can choose a **login method** for your users. Options are including, by email, mobile, or social, just using a username or the custom method you specify. For simplicity, you can choose the **Email** and **Passwordless** options:

![sign-in methods in Authgear](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8evbdgmsabi78sxck0vw.png)

## Part 2: Add Authentication to your web page

Follow the steps to create a simple **SPA app** and learn how to use [Authgear Web SDK](https://docs.authgear.com/get-started/single-page-app/website) to integrate Authgear into your application. You can also view a [full-source code](https://github.com/authgear/authgear-example-spa-js) on the GitHub repo. 

### Prerequisites

Before we start, ensure you have Node.js installed in your system. If not, download and install it from the [official website](https://nodejs.org/en/download/).

### Create a basic web server

In this part, you'll make a simple **website server** to host the SPA app using [ExpressJS](https://expressjs.com/). We'll also use it to serve our HTML page and any assets it needs, like JavaScript, CSS, and so on. Start with making a new folder on your computer to keep the app’s source code (In the example, we call it `authgear-spa-js-login`). Then, initialize a new NPM project by running the following command:

```jsx
npm init -y
```

Next, we install two required packages:

```jsx
npm install express
```

Also, install `[nodemon](https://npmjs.org/package/nodemon)` so that our server can be restarted automatically on any code changes in dev mode:

```jsx
npm install -D nodemon
```

Next, open the `package.json` file and edit scripts entry to have `start` and `dev` commands like the below:

```json
{
  // ...
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  },
  // ...
}
```

Now you can run the app in two modes: prod and dev. 

For example, `npm run dev` will run the application using `nodemon`, monitoring for changes as we modify files.

### Creating server.js

Create a new file `server.js` in the root of the project and populate it with the following code:

```json
const express = require("express");
const { join } = require("path");
const app = express();

// Serve static assets from the /public folder
app.use(express.static(join(__dirname, "public")));

// Endpoint to serve the configuration file
app.get("/authgear_config.json", (req, res) => {
  res.sendFile(join(__dirname, "authgear_config.json"));
});

// Serve the index page for all other requests
app.get("/*", (_, res) => {
  res.sendFile(join(__dirname, "index.html"));
});

// Listen on port 3000
app.listen(3000, () => console.log("Application running on port 3000"));
```

### Create a basic HTML page

Create a `index.html` file in the root of the project and add the following content to the created file:

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Authgear SPA SDK Sample</title>
    <link rel="stylesheet" type="text/css" href="/css/main.css" />
  </head>

  <body>
    <h2>SPA Authentication Sample</h2>
    <p>Welcome to our page!</p>
    <button id="btn-login" disabled="true" onclick="login()">Log in</button>
    <button id="btn-logout" disabled="true" onclick="logout()">Log out</button>
    <script src="js/app.js"></script>
    <script src="https://unpkg.com/@authgear/web@2.2.0/dist/authgear-web.iife.js"></script>
  </body>
</html>
```

To keep the demo simple, we do not use a package manager such as [Webpack](https://webpack.js.org/), we will retrieve the Authgear Web SDK from Authgear's CDN using IIFE(Immediately-invoked Function Expression) bundle. We can reference a script in our HTML directly:

```html
<script src="https://unpkg.com/@authgear/web@2.2.0/dist/authgear-web.iife.js"></script>
```

> You can install the Authgear Web SDK as a dependency of your application, it is useful if you are building React or React Native apps. See how to [install the package](https://docs.authgear.com/get-started/single-page-app/website#install-the-authgear-web-sdk).
> 

### Create a main.css file

Create a new folder called `public` folder in the project root folder and create another folder called `css` inside the `public` folder. Add a new file in there called `main.css`. This will be used to determine how the log-in and log-out button elements will be hidden on the main page depending on whether a user is authenticated or not.

Open the newly-created `public/css/main.css` file and add the following CSS:

```css
.hidden {
    display: none;
}
  
label {
    margin-bottom: 10px;
    display: block;
}
```

After creating an HTML file and applying CSS styles, see now how our page looks like by running `npm run dev` and accessing it at [http://localhost:3000](http://localhost:3000/).

![Authgear SPA Authentication custom apge](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n774s7j2tsvi7hzhu3or.png)

### Create an app.js file

To add some action to the page, we create a new directory in the `public` folder called `js`, and add a new file in there called `app.js`. Copy and paste the following JS code that reads `authgear_config.json` file Authgear app specific values (`endpoint` and `clientId`) from the endpoint using `fetchAuthConfig` function. Also, it configures a new Authgear client, and defines login and logout logic:

```jsx
let authgearClient = null;

const fetchAuthConfig = () => fetch("/authgear_config.json");

const configureClient = async () => {
    const response = await fetchAuthConfig();
    const config = await response.json();
    authgearClient = window.authgear.default;

    await authgearClient.configure({
        endpoint: config.endpoint,
        clientID: config.clientID,
        sessionType: "refresh_token",
    }).then(
        () => {
            console.log("Authgear client successfully configured!");
        },
        (err) => {
            console.log("Failed to configure Authgear");
        }
    );
};

const login = async () => {
    await authgearClient
        .startAuthentication({
            redirectURI: window.location.origin,
            prompt: "login",
        })
        .then(
            () => {
                console.log("Logged in!");
            },
            (err) => {
                console.log("Log in failed", err);
            }
        );
};

const logout = () => {
    authgearClient
    .logout({
      redirectURI: window.location.origin,
    })
    .then(
      () => {
        console.log("Logged out successfully");
      },
      (err) => {
        console.log("Failed to logout");
      }
    );
};

window.onload = async () => {
    await configureClient();
    updateUI();

    const query = window.location.search;
    if (query.includes("code=")) {

        updateUI();

        window.history.replaceState({}, document.title, "/");
    }
}

const updateUI = async () => {
    const isAuthenticated = authgearClient.sessionState === "AUTHENTICATED";

    document.getElementById("btn-logout").disabled = !isAuthenticated;
    document.getElementById("btn-login").disabled = isAuthenticated;
};
```

## Understanding the whole picture

Let’s breakdown down `app.js` code in the previous section and understand how authentication is achieved with Authgear:

**Configure the Authgear client**

`fetchAuthConfig`: Firstly, this function makes a request to the `/authgear_config.json` endpoint we exposed in `server.js` to fetch Authgear app setting values from `authgear_config.json`file.

`configureClient`: Once we retrieve the configuration information for the Authgear client from the `authgear_config.json` file and we set up the Authgear client with these settings. It also logs a message to the console, informing whether the configuration was successful or not.

**Login flow**

`login`: The `login` function is called by the **Login** button previously defined in the HTML page. It performs the login action by calling `authgearClient.startAuthentication` Authgear’s function.  It redirects the user to the Auhthgear login page. After the user logs in successfully, they will be redirected back to the same page we set in `redirectURI`. Run the project and click the **Login** button. You should be taken to the **Authgear Login Page** configured for your application. Go ahead and create a new user or log in using an email (we specified the Passwordless Email login method in the first part). When you try to log in with your email, you should receive a [magic link](https://docs.authgear.com/strategies/email-login-link) to your email box to confirm login operation.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oep564pxx4mwfui0o1zl.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vl4ivccng11bx1ot9tjs.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sit14egbwweauofhb4bb.png)

After authenticating successfully, you will be redirected to the page you were before.

**Logout flow**

`logout`: This function logs the user out and redirects them back to the original page (at [http://localhost:3000](http://localhost:3000/)). It uses Authgear’s `logout` function and logs a message to the console indicating the result of the operation.

**Update the UI**

`window.onload`: This is a function that runs when the page loads. It configures the Authgear client and updates the UI. If the page's URL contains a "code=" which means the user is authenticated (`code` query will be received from Authgear server), it updates the UI again and removes the "code=" from the URL.

**Evaluate the authentication state**

`updateUI`: This function updates the status of the login and logout buttons based on whether the user is authenticated or not. In Authgear, you can check if the user has logged in or not with `sessionState` attribute. If the user is authenticated, we disable the login button and enable the logout button, and vice versa if the user is not authenticated.

## Summary

Throughout the post, you learned how you can quickly add passwordless email-based authentication to any JavaScript web page in just 10 minutes using Authgear. There's much more you can do with Authgear, for example, you can obtain the [current user info](https://docs.authgear.com/get-started/single-page-app/website#fetching-user-info) through SDK, or if you needed to securely communicate from your web page to a backend API, you can include an [access token](https://docs.authgear.com/get-started/single-page-app/website#calling-an-api) to the HTTP requests to your application server.

### Related resources

- [Authentication-as-a-Service: What Is It and Why You Need It](https://www.authgear.com/post/authentication-as-a-service)
- [Frictionless Authentication: What Is It & How To Implement It?](https://www.authgear.com/post/frictionless-authentication)

### Recommended content

- [Simplifying Authentication Integration For Developers With Authgear SDKs](https://www.authgear.com/post/simplifying-authentication-integration-with-authgear-sdks)
- [Social Login - Why You Should Implement It](https://www.authgear.com/post/social-login-guide)

### Community

🙋 [Join the Authgear Community on Discord](https://discord.gg/Kdn5vcYwAS)

🐦 [Follow on Twitter](https://twitter.com/authgear)

📝 [Ask questions](https://github.com/orgs/authgear/discussions/)

💁 [Check out open-source SDKs](https://github.com/authgear)

### About the author

Visit my blog: [www.iambobur.com](https://www.iambobur.com/)