Make any Website Authenticated
Tags: webdev, architecture, devops, tutorial
Published: 2023-03-20 02:20:40

Authentication is always an important topic, basically, any website needs authentication function. Traditionally, we need to maintain our own database, frontend, backend and middleware to achieve complete authentication. But thanks to OAuth, we now have many easy options, such as using Google accounts for authentication.

In this article, we would like to introduce a way to make any website have Google authentication without any modification.

Why is there a need for this? Sometimes we can easily deploy a tool to the cloud, but we don't want the tool to be available for public access, so we want to add authentication to it. However, we don't want to modify the tool's code, so we're attempting to find a more efficient way to do this.

For example, [Apache Flink](https://flink.apache.org/) is a powerful and easy to develop streaming framework that provides a fully functional web portal. Nevertheless, the web portal has no authentication mechanism, so anyone who can access it can upload jobs.

The [official documentation](https://nightlies.apache.org/flink/flink-docs-release-1.16/docs/deployment/security/security-ssl/#external--rest-connectivity) recommends several approaches to mitigate this downside, but those approaches are too lightweight, on the other hand, to provide a full authentication mechanism, Flink supports Kerberos integration which is too heavy. Therefore, we need a plugin that makes it easy for a website to support common authentication.

## Solution Concept


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



From the above diagram, we can find out a user does not access the service directly, but through a Proxy, which verifies and determines whether to allow access.

Therefore, we do not need to modify the code of the service, we just need to plug a Proxy in front to achieve our goal.

In fact, there are many Proxies that provide this function, in this article we choose the most common one [OAuth2 Proxy](https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview), and use Google OAuth as an example.

## Setup Step by Step

First, we need to go to [Google Cloud Console](https://console.cloud.google.com/) to create a new project, the process is not difficult, just fill it out.

Next, navigate to `Credentials` under `API & Service` and create a new credential. There is only one field that needs careful consideration, `Redirect URL`, here fill in the `http://localhost:4180/oauth2/callback` that is needed for the example.

Please remember the `Client ID` and `Client Secret` after you finish creating, we will need them later.

Now, let's use a simple web app as an example, which is the `hello-app` provided by Google.

```yaml
version: '3'

services:
  hello-world:
    image: gcr.io/google-samples/hello-app:1.0
    ports:
      - "8080:8080"
```

Running this `docker-compose.yml` should start hello world, and you can see the corresponding message at `http://localhost:8080`. At this point, the web app is working without authentication.

Let's add a Proxy to implement authentication.

```yaml
services:
  oauth2-proxy:
    ports:
      - "4180:4180"
    image: bitnami/oauth2-proxy:7.3.0
    command:
      - --http-address
      - 0.0.0.0:4180
    environment:
      OAUTH2_PROXY_UPSTREAMS: "http://hello-world:8080/"
      OAUTH2_PROXY_CLIENT_ID: <YOUR_CLIENT_ID>
      OAUTH2_PROXY_CLIENT_SECRET: <YOUR_CLIENT_SECRET>
      OAUTH2_PROXY_COOKIE_SECRET: <A_STORNG_SALT>
      OAUTH2_PROXY_HTTPS_REDIRECT: "false"
      OAUTH2_PROXY_EMAIL_DOMAINS: "*"
      OAUTH2_PROXY_PROVIDER: "google"
      OAUTH2_PROXY_REDIRECT_URL: "http://localhost:4180/oauth2/callback"
    restart: always
```

There are three fields to fill in this example, including the `Client ID` and `Client Secret` just mentioned, as well as the secret needed by a proxy, if there is no special need, then just generate it. I am using a Python script to generate, in fact, there are many ways, choose the one you are familiar with.

```python
import secrets
print(secrets.token_hex(16))
```

Just launch this docker compose directly after completion. You can find that if you access `http://localhost:4180`, you will be redirected to Google Authentication. Once authenticated, you can see the original hello world result.

Finally, we can close the originally opened 8080 port. Here is a complete `docker-compose.yml`, copy and paste it directly with minor modifications and it will work.

```yml
version: '3'

services:
  hello-world:
    image: gcr.io/google-samples/hello-app:1.0
    ports:
      - "8080"

  oauth2-proxy:
    ports:
      - "4180:4180"
    image: bitnami/oauth2-proxy:7.3.0
    command:
      - --http-address
      - 0.0.0.0:4180
    environment:
      OAUTH2_PROXY_UPSTREAMS: "http://hello-world:8080/"
      OAUTH2_PROXY_CLIENT_ID: <YOUR_CLIENT_ID>
      OAUTH2_PROXY_CLIENT_SECRET: <YOUR_CLIENT_SECRET>
      OAUTH2_PROXY_COOKIE_SECRET: <A_STORNG_SALT>
      OAUTH2_PROXY_HTTPS_REDIRECT: "false"
      OAUTH2_PROXY_EMAIL_DOMAINS: "*"
      OAUTH2_PROXY_PROVIDER: "google"
      OAUTH2_PROXY_REDIRECT_URL: "http://localhost:4180/oauth2/callback"
    restart: always
```

If the function is not working properly, it is possible that Google's OAuth client needs start time, wait for it a little.

## Conclusion

This article is a real example of what can be done, and it is quite straightforward.

Nevertheless, it is important to accomplish our goal to add authentication to any web app. For this example, we chose Google OAuth as the easiest to implement, but actually OAuth Proxy supports a lot of IDPs, and there is a complete list in the [official document](https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider).

To understand this article, you don't even need any background knowledge of OAuth, just follow the steps. Enjoy.