This is a JWK Set client proxy, JCP for short. It is used to validate JWTs that were signed by a key that lives in a remote JWK Set. JCP caches the JWK Set in memory and automatically refreshes the JWK Set as configured.
This project serves a few primary use cases:
- The language or shell a program is written in does not have an adequate JWK Set client. Validate JWTs with
curl
? Why not? - Restrictive networking policies prevent a program from accessing the remote JWK Set directly.
- Many co-located services need to validate JWTs that were signed by a key that lives in a remote JWK Set.
It is recommended that JCP is hosted in the same environment (data center) as the program verifying JWTs to reduce latency.
flowchart LR
subgraph Public Internet
J[Remote JWK Set]
end
subgraph Your Datacenter
Y[Your code]
JCP
end
Y-->JCP
JCP-->Y
JCP-->J
J-->JCP
This proxy server implements a Swagger 2.0 and OpenAPI 3 specification. Please see swagger.yml
for the Swagger 2.0
specification and openapi.yml
for the OpenAPI 3 specification.
These specification files can be used to generate client code for your favorite language. However, there is only one small endpoint for JWT validation so hand-coding a client is reasonable.
This project can be installed via a Docker or using the Go toolchain.
Pull the image:
docker pull micahparks/jcp
See docker-compose.yml
for a working Docker Compose example.
Confirm you have Go installed. The minimum required version can be found in go.mod
.
go install github.com/MicahParks/jcp/cmd/proxy@latest
Or you can compile the by downloading this repository, making it your current working directory and running the below commands:
cd cmd/proxy/
go build
After these commands have been run, the proxy
executable will be in the cmd/proxy/
directory.
Below is a table of JWT registered claims and the validation behavior of JCP.
JWT Validation Type | Behavior |
---|---|
Cryptographic signature | automatic |
alg header |
automatic |
exp claim |
automatic |
iat claim |
automatic |
nbf claim |
automatic |
aud claim |
per request |
iss claim |
per request |
sub claim |
per request |
This project is configured via JSON. This program will check three places for this configuration JSON on startup in this order:
- The
CONFIG_JSON
environment variable's raw contents. - The
CONFIG_PATH
environment variable will be read. If non-empty, it will attempt to parse the file at that path. - The
config.json
file in the current working directory.
{
"jwks": {
"https://example.com/jwks.json": {
"refreshInterval": "1h",
"refreshTimeout": "10s"
}
},
"listenAddress": ":8080",
"logFormat": "json",
"requestMaxBytes": 1048576
}
JSON Attribute | Description | Example | Default Value | Required |
---|---|---|---|---|
jwks |
An object mapping remote JWK Set URLs to their options. | see above | none | required |
refreshInterval |
The amount of time to wait before automatically refreshing the remote JWK Set resource. It uses Go syntax for time.ParseDuration . |
1h30m5s |
1h |
optional |
refreshTimeout |
The amount of time to wait failing a remote JWK Set refresh due to a timeout. It uses Go syntax for time.ParseDuration . |
5s |
10s |
optional |
listenAddress |
The address to listen on. It uses Go syntax for net.Listen . |
:3000 |
:8080 |
optional |
logFormat |
The format to log in. This determines which zap output logging is used. Valid values are human and json . |
human |
json |
optional |
requestMaxBytes |
The maximum number of bytes to read from the request body. | 10000 |
1048576 |
optional |
For most use cases, ensure all JWK Set URLs are HTTPS to prevent MITM attacks.
This project currently has greater than 90%
test coverage:
$ go test -cover -race
PASS
coverage: 91.1% of statements
ok github.com/MicahParks/jcp 0.043s
Run these commands in the listed order in separate terminals.
Start a local JWK Set server:
go run cmd/local_jwkset/main.go
Start the JCP server (debugger instructions not shown):
CONFIG_PATH=config.local.json go run cmd/proxy/main.go
This project was built on the following JSON Object Signing and Encryption (JOSE) related libraries: