TL;DR :

Motivation

User management is a problem. Especially if you are trying to accomplish a simple task but it requires authentication/authorization mechanism. In this case you don’t have many options, if you have time constraint then you go with Basic Authentication, which is very basic, easy to break, and not recommended to use. If you have to employ more security, then you might try to implement an authentication/user management system; which doubles the complexity of your simple system.

My current company, as well as previous ones, uses Google for company emails, therefore it’s very convenient to use these emails to authenticate people.

Installation Steps

I will show briefly what is required to install here, you can find the exact installation steps in my ansible configuration from here. Requirements for nginx with google authentication are:

  • nginx with lua support
  • cjson
  • resty.http

I have extra a few requirements for nginx which are required almost all applications:

At the time of this blogpost was published, following versions were available & stable for above requirements:

The download, extraction, source building steps can be found in my ansible configuration.

Nginx installation

Assuming the steps in my ansible configuration has been followed, after extracting & building the sources, we need to configure nginx to run with lua:

export LUAJIT_LIB=/opt/nginx-source/luajit-2.0.5/lib
export LUAJIT_INC=/opt/nginx-source/luajit-2.0.5/include/luajit-2.0
./configure --prefix=/opt/nginx \
         --with-ld-opt="-Wl,-rpath,/opt/nginx-source/luajit-2.0.5/lib" \
         --add-module=/opt/nginx-source/ngx_devel_kit-0.3.0 \
         --add-module=/opt/nginx-source/lua-nginx-module-0.10.11 \
         --with-http_ssl_module

And then install nginx:

cd /opt/nginx-source/nginx-1.12.2 
export LUAJIT_LIB=/opt/nginx-source/luajit-2.0.5/lib
export LUAJIT_INC=/opt/nginx-source/luajit-2.0.5/include/luajit-2.0
make install

This installation process creates nginx binary under /opt/nginx/sbin/nginx and all required nginx configurations under /opt/nginx/conf/.

Google Authentication Usage

Cloudflare example is very extensive and easy to setup with the provided Docker image. Basically after adding these lines to your nginx configuration, you are done:

lua_package_path '/etc/nginx/lua/?.lua;';
server {
...

  set $ngo_client_id         "abc-def.apps.googleusercontent.com";
  set $ngo_client_secret     "abcdefg-123-xyz";
  set $ngo_token_secret      "a very long randomish string";
  set $ngo_secure_cookies    "true";
  set $ngo_http_only_cookies "true";

  access_by_lua_file "/etc/nginx/lua/nginx-google-oauth/access.lua";

...
}

If you have configured your Google project properly, you should be redirected to Google authentication & back again. Only you & the people who share the same domain with you can be granted access. (except of course generic domains like @gmail.com, I mean the company domains here.)


Let’s see some good usages now:

Selectively securing endpoints

Let’s say you have a public application and you want to secure only certain endpoints, like /admin. Then your nginx configuration should look like this:

lua_package_path '/etc/nginx/lua/?.lua;';
server {
...

  set $ngo_client_id         "abc-def.apps.googleusercontent.com";
  set $ngo_client_secret     "abcdefg-123-xyz";
  set $ngo_token_secret      "a very long randomish string";
  set $ngo_secure_cookies    "true";
  set $ngo_http_only_cookies "true";


  location /admin {
  	access_by_lua_file "/etc/nginx/lua/nginx-google-oauth/access.lua";
	root ...;
  }

  location /public {
	root ...;
  }

...
}

By copying the access_by_lua_file directive to under location blocks, you can make that location guarded by Google authentication. In this example, every request going to /admin endpoint will require Google authentication, while /public endpoint will not.

Custom authorization

This example handles the authentication, you can implement a custom authorization mechanism by proxying the requests to a middleware:

lua_package_path '/etc/nginx/lua/?.lua;';
server {
...

  set $ngo_client_id         "abc-def.apps.googleusercontent.com";
  set $ngo_client_secret     "abcdefg-123-xyz";
  set $ngo_token_secret      "a very long randomish string";
  set $ngo_secure_cookies    "true";
  set $ngo_http_only_cookies "true";
  set $ngo_user				 "unknown@example.com";
  access_by_lua_file 		 "/etc/nginx/lua/nginx-google-oauth/access.lua";

  location / {
    proxy_set_header "google-user" $ngo_user;
	proxy_pass 127.0.0.1:8080;
  }

...
}

Assuming there is an application running at port 8080. In this application, you can check google-user header and see who is making the request. Then you can use it to grant permissions to the user, or not. I am planning to implement a simple application to showcase authorization with Google authentication for my next blog post.

Conclusion

Google authentication within nginx made the development environment flow very effective in my current company. One less password to remember, one less user to manage, less possibility of security/password breach, and everybody is happier than a password-oriented system.