├── .env ├── .gitignore ├── README.md ├── api └── node-proxy.js ├── now.json ├── package.json └── yarn.lock /.env: -------------------------------------------------------------------------------- 1 | ORIGIN=https://macao20.com 2 | USERNAME=user 3 | PASSWORD=password -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .now -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simple-basic-http-auth-proxy-vercel 2 | 3 | 🔐▲ A simple basic HTTP Auth Proxy for Vercel, ideal for adding simple password protection to staging applications. 4 | 5 | This project uses [node-http-proxy](https://github.com/http-party/node-http-proxy) inside a serverless function to add 6 | basic password protection to ORIGIN site via HTTP Auth, requiring no code change to the ORIGIN deployment. This is designed 7 | to add simple password protection to deployments during the UAT stage. 8 | 9 | ## Getting Started 10 | 11 | 1. Deploying this project to Vercel Now
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/bbiHQ/simple-basic-http-auth-proxy-vercel/tree/master/) 12 | 13 | 2. Adding the following ENV variables for Production: 14 | 15 | + `ORIGIN`: The URL of your stage deployment, best to point it to a custom domain assigned to the UAT branch. 16 | + `USERNAME`: The username required to login. 17 | + `PASSWORD`: The password required to login. 18 | 19 | 3. Redeploy app using the updated ENV variables. 20 | 21 | ## Local Usage 22 | 23 | 1. Run `yarn install` to install the require packages. 24 | 2. Update `.env` file with values required. 25 | 3. Run `now dev`. 26 | 27 | ## Demo 28 | 29 | The deployment at https://simple-basic-http-auth-proxy-vercel.now.sh adds password protection around Google search. 30 | 31 | Username: williamli 32 | 33 | Password: password 34 | -------------------------------------------------------------------------------- /api/node-proxy.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const httpProxy = require('http-proxy'); 3 | const auth = require('basic-auth'); 4 | 5 | // Create a proxy server with custom application logic 6 | const proxy = httpProxy.createProxyServer({changeOrigin: true, autoRewrite: true, hostRewrite: true, followRedirects: true}); 7 | 8 | 9 | const server = http.createServer(function(req, res) { 10 | 11 | // load from ENVs 12 | const origin = process.env.ORIGIN; 13 | const password = process.env.PASSWORD; 14 | const username = process.env.USERNAME; 15 | 16 | 17 | 18 | // console.log('ORIGIN:', process.env.ORIGIN); 19 | 20 | const credentials = auth(req); 21 | if (!credentials || !isAuthed(credentials, username, password)) { 22 | res.statusCode = 401; 23 | res.setHeader('WWW-Authenticate', 'Basic realm="example"'); 24 | res.end('Access denied.'); 25 | } else { 26 | // do nothing 27 | // res.end('Access granted') 28 | } 29 | 30 | 31 | proxy.on('proxyRes', function(proxyRes, req, res) { 32 | // console.log('Raw [target] response', JSON.stringify(proxyRes.headers, true, 2)); 33 | 34 | proxyRes.headers['x-proxy'] = "simple-basic-http-auth-proxy-vercel"; 35 | 36 | // console.log('Updated [proxy] response', JSON.stringify(proxyRes.headers, true, 2)); 37 | 38 | }); 39 | proxy.web(req, res, { target: `${origin}` }); 40 | 41 | }); 42 | 43 | const port = process.env.AWS_LAMBDA_RUNTIME_API.split(':')[1]; 44 | console.log(`simple-basic-http-auth-proxy for Vercel started on port ${port}`); 45 | server.listen(port); 46 | 47 | 48 | const isAuthed = function (credentials, username, password) { 49 | return credentials.name === username && credentials.pass === password; 50 | } -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "functions": { 4 | "api/node-proxy.js": { 5 | "memory": 1024 6 | } 7 | }, 8 | "routes": [ 9 | {"src": "/(.*)", "dest": "/api/node-proxy.js"} 10 | ] 11 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-basic-http-auth-proxy-vercel", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/bbiHQ/simple-basic-http-auth-proxy-vercel.git" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/bbiHQ/simple-basic-http-auth-proxy-vercel/issues" 18 | }, 19 | "homepage": "https://github.com/bbiHQ/simple-basic-http-auth-proxy-vercel#readme", 20 | "dependencies": { 21 | "basic-auth": "^2.0.1", 22 | "http-proxy": "^1.18.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | basic-auth@^2.0.1: 6 | version "2.0.1" 7 | resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" 8 | integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== 9 | dependencies: 10 | safe-buffer "5.1.2" 11 | 12 | debug@^3.0.0: 13 | version "3.2.6" 14 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 15 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 16 | dependencies: 17 | ms "^2.1.1" 18 | 19 | eventemitter3@^4.0.0: 20 | version "4.0.0" 21 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" 22 | integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== 23 | 24 | follow-redirects@^1.0.0: 25 | version "1.11.0" 26 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb" 27 | integrity sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA== 28 | dependencies: 29 | debug "^3.0.0" 30 | 31 | http-proxy@^1.18.0: 32 | version "1.18.0" 33 | resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" 34 | integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== 35 | dependencies: 36 | eventemitter3 "^4.0.0" 37 | follow-redirects "^1.0.0" 38 | requires-port "^1.0.0" 39 | 40 | ms@^2.1.1: 41 | version "2.1.2" 42 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 43 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 44 | 45 | requires-port@^1.0.0: 46 | version "1.0.0" 47 | resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" 48 | integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= 49 | 50 | safe-buffer@5.1.2: 51 | version "5.1.2" 52 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 53 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 54 | --------------------------------------------------------------------------------