An authentication module for Apache httpd using JSON Web Tokens
Clone or download
Permalink
Failed to load latest commit information.
acinclude.d
tests fix run tests permissions for non-root Sep 7, 2017
.gitignore Fix tests to support base64 shared secret, add autoconf gitignore ent… Jun 24, 2017
.travis.yml Try trigger travis build Sep 2, 2017
AUTHORS
COPYING Implemented autoconf. Mar 1, 2017
ChangeLog Implemented autoconf. Mar 1, 2017
INSTALL Implemented autoconf. Mar 1, 2017
Makefile.am Fixed temporary module name to auth_jwt. Mar 1, 2017
NEWS Implemented autoconf. Mar 1, 2017
README Implemented autoconf. Mar 1, 2017
README.md requires libz to build (Ubuntu 18.3) Jul 31, 2018
configure.ac
mod_authnz_jwt.c Fix get_decode_key for shared secrets Jun 26, 2018

README.md

mod_authnz_jwt

Authentication module for Apache httpd with JSON web tokens (JWT).

Build Status

More on JWT : https://jwt.io/

Supported algorithms : HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512

Built-in checks : iss, aud, exp, nbf

Configurable checks : every claims contained in the token (only string and array)

This module is able to deliver JSON web tokens containing all public fields (iss, aud, sub, iat, nbf, exp), and the private field "user". Authentication process is carried out by an authentication provider and specified by the AuthJWTProvider directive.

On the other hand, this module is able to check validity of token based on its signature, and on its public fields. If the token is valid, then the user is authenticated and can be used by an authorization provider with the directive "Require valid-user" to authorize or not the request.

Although this module is able to deliver valid tokens, it may be used to check tokens delivered by a custom application in any language, as long as a secret is shared between the two parts. This feature is possible because token-based authentication is stateless.

Build Requirements

Quick start

Installation from sources

sudo apt-get install libtool pkg-config autoconf libssl-dev check libjansson-dev
git clone https://github.com/benmcollins/libjwt
cd libjwt
git checkout tags/v1.8.0
autoreconf -i
./configure
make
sudo make install
cd ..
sudo apt-get install apache2 apache2-dev libz-dev
git clone https://github.com/AnthonyDeroche/mod_authnz_jwt
cd mod_authnz_jwt
autoreconf -ivf
./configure
make
sudo make install

Generate EC keys

openssl ecparam -name secp256k1 -genkey -noout -out ec-priv.pem
openssl ec -in ec-priv.pem -pubout -out ec-pub.pem

Generate RSA keys

openssl genpkey -algorit RSA -out rsa-priv.pem -pkeyopt rsa_keygen_bits:4096
openssl rsa -pubout -in rsa-priv.pem -out rsa-pub.pem

Authentication

The common workflow is to authenticate against a token service using for instance username/password. Then we reuse this token to authenticate our next requests as long as the token remains valid.

Using username/password

You can configure the module to deliver a JWT if your username/password is correct. Use "AuthJWTProvider" to configure which providers will be used to authenticate the user.

Authentication modules are for instance:

The delivered token will contain your username in a field named "user" (See AuthJWTAttributeUsername to override this value) as well as public fields exp, iat, nbf and possibly iss and aud according to the configuration.

A minimal configuration might be:

AuthJWTSignatureAlgorithm HS256
AuthJWTSignatureSharedSecret Q0hBTkdFTUU=
AuthJWTIss example.com
<Location /demo/login>
	SetHandler jwt-login-handler
	AuthJWTProvider file
	AuthUserFile /var/www/jwt.htpasswd
</Location>

Using a JWT

A secured area can be accessed if the provided JWT is valid. JWT must be set in Authorization header. Its value must be "Bearer ".

If the signature is correct and fields are correct, then a secured location can be accessed.

Token must not be expired (exp), not processed too early (nbf), and issuer/audience must match the configuration.

A minimal configuration might be:

AuthJWTSignatureAlgorithm HS256
AuthJWTSignatureSharedSecret Q0hBTkdFTUU=
AuthJWTIss example.com
<Directory /var/www/html/demo/secured/>
	AllowOverride None
	AuthType jwt
	AuthName "private area"
	Require valid-user
</Directory>

Authorization

You can use the directive Require jwt-claim key1=value1 key2=value2. Putting multiple keys/values in the same require results in an OR. You can use RequireAny and RequireAll directives to be more precise in your rules.

In case your key is an array, you can use the directive Require jwt-claim-array key1=value1 to test that "value1" is contained in the array pointed by the key "key1".

Examples:

AuthJWTSignatureAlgorithm HS256
AuthJWTSignatureSharedSecret Q0hBTkdFTUU=
AuthJWTIss example.com
<Directory /var/www/html/demo/secured/>
	AllowOverride None
	AuthType jwt
	AuthName "private area"
	Require jwt-claim user=toto
    Require jwt-claim-array groups=group1
</Directory>

How to get authenticated user in your apps?

If your app is directly hosted by the same Apache than the module, then you can read the environment variable "REMOTE_USER".

If the apache instance on which the module is installed acts as a reverse proxy, then you need to add a header in the request (X-Remote-User for example). We use mod_rewrite to do so. For your information, rewrite rules are interpreted before authentication. That's why why need a "look ahead" variable which will take its final value during the fixup phase.

RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader set X-Remote-User "%{RU}e" env=RU

Configuration examples

This configuration is given for tests purpose. Remember to always use TLS in production.

With HMAC algorithm:

<VirtualHost *:80>
	ServerName example.com
	DocumentRoot /var/www/html/

	# default values
	AuthJWTFormUsername user
	AuthJWTFormPassword password
	AuthJWTAttributeUsername user
	
	AuthJWTSignatureAlgorithm HS256
	AuthJWTSignatureSharedSecret Q0hBTkdFTUU=
	AuthJWTExpDelay 1800
	AuthJWTNbfDelay 0
	AuthJWTIss example.com
	AuthJWTAud demo
	AuthJWTLeeway 10

	<Directory /var/www/html/demo/secured/>
		AllowOverride None
		AuthType jwt
		AuthName "private area"
		Require valid-user
	</Directory>
	
	
	<Location /demo/login>
		SetHandler jwt-login-handler
		AuthJWTProvider file
		AuthUserFile /var/www/jwt.htpasswd
	</Location>

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

With EC algorithm:

<VirtualHost *:80>
	ServerName example.com
	DocumentRoot /var/www/html/

	# default values
	AuthJWTFormUsername user
	AuthJWTFormPassword password
	AuthJWTAttributeUsername user
	
	AuthJWTSignatureAlgorithm ES256
	AuthJWTSignaturePublicKeyFile /etc/pki/auth_pub.pem
	AuthJWTSignaturePrivateKeyFile /etc/pki/auth_priv.pem
	AuthJWTExpDelay 1800
	AuthJWTNbfDelay 0
	AuthJWTIss example.com
	AuthJWTAud demo
	AuthJWTLeeway 10

	<Directory /var/www/html/demo/secured/>
		AllowOverride None
		AuthType jwt
		AuthName "private area"
		Require valid-user
	</Directory>
	
	
	<Location /demo/login>
		SetHandler jwt-login-handler
		AuthJWTProvider file
		AuthUserFile /var/www/jwt.htpasswd
	</Location>

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Documentation

Directives

AuthJWTProvider
  • Description: Authentication providers used
  • Context: directory
AuthJWTSignatureAlgorithm
  • Description: The algorithm to use to sign tokens
  • Context: server config, directory
  • Default: HS256
  • Possibles values: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512
  • Mandatory: yes
AuthJWTSignatureSharedSecret
  • Description: The secret to use to sign tokens with HMACs. It must be base64 encoded.
  • Context: server config, directory
  • Mandatory: no
AuthJWTSignaturePublicKeyFile
  • Description: The file path of public key used with either RSA or EC algorithms.
  • Context: server config, directory
  • Mandatory: no
AuthJWTSignaturePrivateKeyFile
  • Description: The file path of private key used with either RSA or EC algorithms.
  • Context: server config, directory
  • Mandatory: no
AuthJWTIss
  • Description: The issuer of delivered tokens
  • Context: server config, directory
  • Mandatory: no
AuthJWTAud
  • Description: The audience of delivered tokens
  • Context: server config, directory
  • Mandatory: no
AuthJWTExpDelay
  • Description: The time delay in seconds after which delivered tokens are considered invalid
  • Context: server config, directory
  • Default: 1800
  • Mandatory: no
AuthJWTNbfDelay
  • Description: The time delay in seconds before which delivered tokens must not be processed
  • Context: server config, directory
  • Default: 0
  • Mandatory: no
AuthJWTLeeway
  • Description: The leeway to account for clock skew in token validation process
  • Context: server config, directory
  • Default: 0
  • Mandatory: no
AuthJWTFormUsername
  • Description:The name of the field containing the username in authentication process
  • Context: server config, directory
  • Default: user
  • Mandatory: no
AuthJWTFormPassword
  • Description:The name of the field containing the password in authentication process
  • Context: server config, directory
  • Default: password
  • Mandatory: no
AuthJWTAttributeUsername
  • Description:The name of the attribute containing the username in the token (used for authorization as well as token generation)
  • Context: server config, directory
  • Default: user
  • Mandatory: no