Implementing JWT Authentication in NGINX Without NGINX Plus

Implementing JWT Authentication in NGINX Without NGINX Plus
Photo by Luca Bravo / Unsplash

Securing web applications often involves verifying the identity of users accessing your resources. JSON Web Tokens (JWT) are a popular solution for this purpose, offering a compact and self-contained way to transmit information securely between parties. While NGINX Plus offers built-in JWT authentication, you can achieve similar functionality without it by leveraging OpenResty and Lua scripting. In this article, we'll guide you through the process of implementing JWT authentication in NGINX using the lua-resty-jwt library.

Prerequisites

Before we begin, ensure you have the following installed:

  1. OpenResty: A high-performance web platform that integrates NGINX and LuaJIT.
  2. lua-resty-jwt: A Lua library for handling JWTs.

Step-by-Step Implementation

1. Install OpenResty

OpenResty is a web application server that extends NGINX with Lua scripting capabilities. Follow the OpenResty installation guide to install it on your system.

2. Install lua-resty-jwt

Next, download and install the lua-resty-jwt library. This library provides the necessary functionality to decode and verify JWTs.

mkdir -p /usr/local/openresty/lualib/resty
cd /usr/local/openresty/lualib/resty
wget https://raw.githubusercontent.com/SkyLothar/lua-resty-jwt/master/lib/resty/jwt.lua

3. Configure NGINX with OpenResty

Edit your NGINX configuration file, typically located at /usr/local/openresty/nginx/conf/nginx.conf or /etc/nginx/nginx.conf. Add the following Lua code to handle JWT authentication:

http {
    lua_shared_dict jwt_cache 10m;

    server {
        listen 80;
        server_name your_server_name;

        location / {
            access_by_lua_block {
                local jwt = require "resty.jwt"
                local jwt_token = ngx.var.http_Authorization

                if not jwt_token then
                    ngx.status = ngx.HTTP_UNAUTHORIZED
                    ngx.say("Missing token")
                    return ngx.exit(ngx.HTTP_UNAUTHORIZED)
                end

                local auth_header_prefix = "Bearer "
                if not jwt_token:find(auth_header_prefix, 1, true) then
                    ngx.status = ngx.HTTP_UNAUTHORIZED
                    ngx.say("Invalid token")
                    return ngx.exit(ngx.HTTP_UNAUTHORIZED)
                end

                jwt_token = jwt_token:sub(auth_header_prefix:len() + 1)
                local jwt_obj = jwt:verify("your_secret_key", jwt_token)

                if not jwt_obj.verified then
                    ngx.status = ngx.HTTP_UNAUTHORIZED
                    ngx.say("Invalid token")
                    return ngx.exit(ngx.HTTP_UNAUTHORIZED)
                end

                ngx.log(ngx.INFO, "User authenticated: " .. jwt_obj.payload.sub)
            }

            proxy_pass http://your_backend;
        }
    }
}

Replace your_server_name with your actual server name and your_secret_key with the secret key used to sign the JWTs.

4. Test the Configuration

After updating the NGINX configuration file, test the configuration to ensure there are no syntax errors:

sudo nginx -t

If the configuration test passes, reload NGINX to apply the changes:

sudo systemctl reload nginx

Detailed Explanation

  • lua_shared_dict jwt_cache 10m;: This directive allocates a shared memory zone for caching JWTs.
  • access_by_lua_block: This block allows Lua code to execute during the access phase of the request.
  • jwt("your_secret_key", jwt_token): This function verifies the JWT using the provided secret key.
  • ngx.var.http_Authorization: This variable retrieves the Authorization header from the request.

Error Handling

It's crucial to handle different types of errors, such as missing tokens, invalid tokens, and expired tokens, to provide appropriate responses to clients. The Lua code in the configuration handles these cases and returns a 401 Unauthorized status with a relevant message.

Securing Your Secret Key

Ensure the secret key is stored securely and not hard-coded directly into the configuration files. Consider using environment variables or a secure vault for storing sensitive information.

Conclusion

By following these steps, you can implement JWT authentication in NGINX without requiring NGINX Plus. This approach leverages the power of OpenResty and Lua scripting to handle JWTs effectively, providing a secure way to authenticate users accessing your web resources.

Implementing JWT authentication enhances the security of your web applications, ensuring only authenticated users can access protected resources. With OpenResty and lua-resty-jwt, you can achieve this without needing the advanced features of NGINX Plus.