Home

Awesome

jcp

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:

  1. The language or shell a program is written in does not have an adequate JWK Set client. Validate JWTs with curl? Why not?
  2. Restrictive networking policies prevent a program from accessing the remote JWK Set directly.
  3. 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

API Specifications

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.

Installation

This project can be installed via a Docker or using the Go toolchain.

Docker

Pull the image:

docker pull micahparks/jcp

See docker-compose.yml for a working Docker Compose example.

Go

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.

Validation features

Below is a table of JWT registered claims and the validation behavior of JCP.

JWT Validation TypeBehavior
Cryptographic signatureautomatic
alg headerautomatic
exp claimautomatic
iat claimautomatic
nbf claimautomatic
aud claimper request
iss claimper request
sub claimper request

Configuration

This project is configured via JSON. This program will check three places for this configuration JSON on startup in this order:

  1. The CONFIG_JSON environment variable's raw contents.
  2. The CONFIG_PATH environment variable will be read. If non-empty, it will attempt to parse the file at that path.
  3. The config.json file in the current working directory.

Configuration JSON structure

{
  "jwks": {
    "https://example.com/jwks.json": {
      "refreshInterval": "1h",
      "refreshTimeout": "10s"
    }
  },
  "listenAddress": ":8080",
  "logFormat": "json",
  "requestMaxBytes": 1048576
}
JSON AttributeDescriptionExampleDefault ValueRequired
jwksAn object mapping remote JWK Set URLs to their options.see abovenonerequired
refreshIntervalThe amount of time to wait before automatically refreshing the remote JWK Set resource. It uses Go syntax for time.ParseDuration.1h30m5s1hoptional
refreshTimeoutThe amount of time to wait failing a remote JWK Set refresh due to a timeout. It uses Go syntax for time.ParseDuration.5s10soptional
listenAddressThe address to listen on. It uses Go syntax for net.Listen.:3000:8080optional
logFormatThe format to log in. This determines which zap output logging is used. Valid values are human and json.humanjsonoptional
requestMaxBytesThe maximum number of bytes to read from the request body.100001048576optional

For most use cases, ensure all JWK Set URLs are HTTPS to prevent MITM attacks.

Test coverage

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

Local debug setup

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

References

This project was built on the following JSON Object Signing and Encryption (JOSE) related libraries: