A reverse proxy which rejects incoming requests which:
authorization HTTP header.authorization header which doesn't contain a JWT.authorization header which contains an expired or invalid JWT.authorization header which contains a JWT which has an unrecognised issuer.authorization header which could not be validated using the public key corresponding to the issuer.iss) value to use for each API client.
example.com.authorization header containing a JWT signed with the private key.Generate a private key. (example_private.pem).
openssl genrsa -out example_private.pem 2048
Extract the public key. (example_public.pem)
openssl rsa -in example_private.pem -outform PEM -pubout -out example_public.pem
You start the proxy passing it a map of issuers to public keys as environment variables or a file.
The JWT passed by the client must meet the following criteria:
The JWT must be signed using the RS256 algorithm.
{
"alg": "RS256",
"typ": "JWT"
}
The payload must contain an issuer agreed between the two parties, and an expiration timestamp.
{
"iss": "custom_issuer.example.com",
"exp": "1504282460"
}
Configuration can be provided by command line flags (specified by -name) or by environment variables.
The URL to proxy requests to.
The HTTP host header to send to the remote endpoint (useful if the remote endpoint is not using DNS).
The TCP port to open up the proxy on.
The location that the proxy should use to respond to health check HTTP requests (defaults to /health).
The prefix to strip from incoming requests applied to the remote URL, e.g to make incoming HTTP request /api/user?id=1 map to outgoing HTTP request /user?id=1
It's possible to set issuer to public key maps by using environment variables alone.
To set the issuer "example.com" to a public key, create two environment variables with a matching suffix for the JWTPROXY_ISSUER_ and JWTPROXY_PUBLIC_KEY_ keys, e.g.:
JWTPROXY_ISSUER_0=example.com
JWTPROXY_PUBLIC_KEY_0=-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxFj26fqmulXntc7kCp9tMs6MEQUsk2r16Jd6k+aZSaLBo0dVgP77q1os10gZT4N0gYH6NsbVqP4+wWAUIDiemhpxq986z5mtB/lGvmHmaQcK/bOnEvcLWinHJZIla1m2RF7diN5/WBRNh8CyYMiW+BV/6dngknBtP7bDpnCkYrySaOQtKRvrech1UFRKgQjD8bprrcUmOFWYrmKe2NCxcQs9RhYuACt3Du2Z4VwVWN2xvL5LlZdWK7jLENe3MkOZU5WcwA7n+K/tulqA9uNRv8cRIL/y8BUwUsUoqBiyVZXQUa7BgE82GoTXtv3uqkN/yZxnlEcaJW5BD1nFzuvuyQIDAQAB-----END PUBLIC KEY-----
The location of a JSON file containing a map of issuers to public keys, e.g.:
JWTPROXY_CONFIG=keys.json
JSON does not support newlines, so the public key value will need to have them replaced with \n in JSON, e.g. by cat dev_pub.pem | tr '\n' '_' | sed 's/_/\\n/g' > dev_pub2.pem
{
"example.com": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxFj26fqmulXntc7kCp9t\nMs6MEQUsk2r16Jd6k+aZSaLBo0dVgP77q1os10gZT4N0gYH6NsbVqP4+wWAUIDie\nmhpxq986z5mtB/lGvmHmaQcK/bOnEvcLWinHJZIla1m2RF7diN5/WBRNh8CyYMiW\n+BV/6dngknBtP7bDpnCkYrySaOQtKRvrech1UFRKgQjD8bprrcUmOFWYrmKe2NCx\ncQs9RhYuACt3Du2Z4VwVWN2xvL5LlZdWK7jLENe3MkOZU5WcwA7n+K/tulqA9uNR\nv8cRIL/y8BUwUsUoqBiyVZXQUa7BgE82GoTXtv3uqkN/yZxnlEcaJW5BD1nFzuvu\nyQIDAQAB\n-----END PUBLIC KEY-----"
}
jwtproxy -remoteURL http://example.com:8080 -keys keys.json
Or you can run the Docker container, using environment variables to pass in required data. In this case, exposing the linked container 'hopeful_pike'.
docker run --link hopeful_pike -p 9090:9090/tcp --rm -e "JWTPROXY_LISTEN_PORT=9090" -e "JWTPROXY_REMOTE_URL=http://hopeful_pike:8080" -v /users/me/keys.json:/keys.json -e "JWTPROXY_CONFIG=keys.json" adrianhesketh/jwtproxy
Use curl to access your local proxy.
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDg2MzkyMjAwIiwiZXhwIjoiMTU4NjM5MjIwMCIsImlzcyI6ImV4YW1wbGUuY29tIn0.McHwUVbe96y-vaTOExPjANm8e8p0v6I7puPf74SV7Jn-QYprrhLlklnBP4MEF77v0LIBUFKgzpOMfldCONId3ktOFOf0117x9iWG3J-Zf6Ni3HinhA9U1pPU7_OhTtkXacmgats8tLWAqmOz46NeyAmHS_dkvodUUPpcHY-AqQtzM4ql6RZpMDstz5dFJWZh9P0_prPknoI-argt2jn-KGajCOIghcGxNarylq5oX62rT9AavavyWGnJW0zLnP9qtIuChzigU542Nbg7y6_E7FaVA2cPICPuiPehn6vVTKuVil0o2SJgFD2J2HQfxa0iDrc8HzbubMGJcw7Vlpkk0w" http://localhost:9090
Generate a JWT with an appropriate payload at [jwt.io], or using a library:
{
"iat": "1486392200",
"exp": "1586392200",
"iss": "example.com"
}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOiIxNDg2MzkyMjAwIiwiZXhwIjoiMTU4NjM5MjIwMCIsIm5hbWUiOiJBZHJpYW4gSGVza2V0aCJ9.d45Or2h-lApJ4FK2pKj0ZIRdDTULsNl1z-V3LfQFvno
To sign and validate using the command line (to compare against the Go implementation):
# SHA256 hash the data.
openssl dgst -sha256 -binary data.json > hash.bin
# base64 encode the hash so that it should match the value of the X-Sha256hash HTTP header.
openssl base64 -e -in hash.bin -out hash.b64
# Sign the hash.
openssl rsautl -in hash.bin -inkey private_test.pem -sign -out signature.bin
# base64 encode the signature so that it should match the value of the X-Signature HTTP header.
openssl base64 -e -in signature.bin -out signature.b64
# Verify the signature.
openssl rsautl -in signature.bin -verify -inkey public_test.pem -pubin > verified.bin
openssl base64 -e -in verified.bin -out verified.b64
# Compare the original hash to the hash created by the verification routine.
# The two files should be equal.
cat hash.b64
cat verified.b64
Content type
Image
Digest
sha256:93be11036…
Size
2.1 MB
Last updated
over 3 years ago
docker pull pdok/jwtproxy