Skip to content

aocks/ox_jwt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

79 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Introduction

The ox_jwt repository provides some simple tools for working with JSON Web Tokens (JWTs) as well as illustrating some use cases with nginx and python.

nginx

For example, the nginx sub-directory contains a fully working minimal example of how you can setup NGINX to only allow access to your locations if the client has a JWT in the URL, header, or browser cookie.

This is useful because:

  1. You can easily protect access to your internal or external servers.
    • For example, requiring a JWT will block hackers trying to brute force username/password combinations.
    • Checking the JWT in NGINX prevents hackers from exploiting vulnerabilities in your application server.
  2. Since NGINX is a widely used open source web server, this approach to security is easy to integrate with most systems.
  3. All of the encryption/decryption used is open source, verifiable, and modifiable by you.

python

The overview slides provide a detailed presentation of what JWTs are and how to use them in python.

You can use JWTs in python with or without nginx. For example, you could have nginx do validation of the JWT and then provide the decoded JWT as a header to further python code. Alternatively, you can do JWT encoding and decoding purely in python.

If you pip install ox_jwt, you can then run the command test_ox_jwt to do a simple local test of encoding JWTs and decoding them with a flask server. See the python files in src/ox_jwt/ to see how the python example works.

Quickstart and Demo

nginx

For a simple test of the nginx system, you can do something like

make test

at the command line to do the following:

  1. Install the npm dependencies listed in nginx/ojwt/package.json using npm install (you will need to have a reasonable version of npm already installed).
  2. Create private/public/test keys in nginx/ojwt/*.pem
  3. Use the keys to create a test JWT in ojwt/prod_test_jwt.txt.
    • This JWT is keyed to the host example.com.
  4. Build the single file javascript bundle in nginx/ojwt/ojwt.js.
    • This is the only file that you need to put onto your NGINX web server. It contains all the encryption/decryption code as well as your public key (but not your private key).
  5. Build and start a simple NGINX docker container using nginx/Dockerfile.
  6. Uses curl to verify that you can only access the protected location in your NGINX server if you have the appropriate JWT.

python

For a test of the python implementation, you can do

pip install ox_jwt

and then run the test_ox_jwt command.

Alternatively, you can clone the GitHub repository via something like

git clone https://github.com/aocks/ox_jwt.git

and then build a virtual env and install dependencies via

cd ox_jwt
python3 -m venv venv_ox_jwt
source venv_ox_jwt/bin/activate
pip install -e .

and then run the tests/demo via:

py.test src/ox_jwt

FAQ

What are some alternatives to ox_jwt for nginx?

Aren’t there some other easy alternatives for nginx?

Not that I am aware of. Most other approaches to JWT validation in your APPLICATION server instead of your NGINX server or proxy or require a commercial (i.e., non-open-source) server.

Why do JWT validation in NGINX?

Plenty of applications do JWT validation and decoding themselves as shown in the python examples. That is a fine and useful thing to do and can also be combined with validating the JWT in NGINX as well.

A few reasons why you might want to do JWT validation in the web server instead of or in addition to the application include:

  1. Reduces load on the application server.
    • Most external systems will be subject to constant attacks and probes by hackers. Using JWT validation where possible prevents these attacks from even getting to the application server which can be useful.
  2. Simplify security audits.
    • Application servers can be complicated which makes reasoning about security in an audit more difficult. By putting a relatively simple JWT validation layer at your NGINX proxy, you can make it easier for your security professionals to audit, maintain, and verify your security.
    • For example, if you have many different application servers written in different languages with different technology stacks, it can be difficult for security professionals to review and manage all of them. By providing JWT validation in the single entry point (i.e., NGINX) to all your applications, you have a potentially cleaner, more modular system.
    • Simplify logging. Monitoring JWT validation failures as well as successful access can be simpler if that is done in a single place.

How do you setup protection?

See the NGINX configuration file in nginx/conf.d/example.conf. Basically you do the following in your NGINX configuration file:

  1. Add a line like js_import conf.d/ojwt.js; near the top of your config.
    • This tells where to find the ojwt.js single file javascript bundle which you build via cd nginx/ojwt && make ojwt.js.
    • The ojwt.js includes your public key.
  2. Add a line like js_set $decoded_ojwt auth_tools.decode_jwt; near the top of your config.
    • This tells NGINX to use the auth_tools.decode_jwt function from ojwt.js to try to decode JWTs from the URL or header or cookie of incoming requests and put the result into the $decoded_ojwt NGINX variable.
  3. Put a block like the following in your NGINX config to return a 401 error if the JWT is not valid:
location /protected {
  if ($decoded_ojwt ~ "^fail.*") {
    return 401 $decoded_ojwt;
  }
}

Once you have the above, all of your protected locations will require valid JWTs but users can still access any locations you choose not to protect as usual.

How can I create a JWT for a user?

You can create JWTs as usual using your private RSA key. As a convenience, ox_jwt provides a simple command line tool to generate JWTs. To access it, simply do something like the following:

cd /path/to/nginx/ojwt/
make private_key.pem  # only need to do this once; or provide your own

node otools.js encode -k private_key.pem \
  -m "my example msg" -h example.com \
  --exp `date +%s --date=tomorrow`
# You can replace the above parameters as you like or omit them.

How is this secure?

When you want to give someone access to a server or area that you have protected, you simply give them a JWT created using your private_key.pem (keep this file secure!). See the above discussion for How can I create a JWT for a user.

The user then provides this JWT in the URL query parameters via something like ?jwt=YOUR_JWT. NGINX will contain the PUBLIC key but not the PRIVATE key. So when the user attempts to gain access, NGINX will verify that the JWT was created by the corresponding private key.

Note that because we use public key cryptography, you do not need to store any secret information on the NGINX server. You simply store the PUBLIC which cannot be used to create new JWTs. Thus if your NGINX server is compromised or non-privileged people have access to the ojwt.js file you deploy, that is not a problem.

Can I see the decoded JWT from NGINX?

The decoded payload will be put into the variable requested. For example, if you use a configuration like nginx/conf.d/example.conf, you can do the following:

  1. Build and start the example dockerized NGINX server via:
    • cd ox_jwt/nginx && run_ojwt_nginx
  2. Use curl to check the token and see the response headers via:
    • make curl_verbose_token_check
  3. The payload of the JWT used (ojwt/prod_test_jwt.txt by default) will be shown in the X-decoded-ojwt response header in JSON format.
  4. Stop the docker container via:
    • make stop_ojwt_nginx

You can view the decoded JWT payload and use it either in NGINX or in your application server.

What if I have another question?

Please create a new issue on GitHub.

About

Simple tools for working with JSON Web Tokens

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors