dmjwk (pronounced "dumb jock") is a simple demo web server that provides a basic Resource Owner Password Credentials Grant OAuth 2 flow that returns a JSON Web Tokens for "authenticated" users, as well as a OAuth 2 Bearer Token API that validates those JWTs. It signs the tokens with a memory-persistent JSON Web Key set.
Caution
This is not a serious IDP. It's designed exclusively for use demoing applications that depend on an IDP. It stores no data, releases all JSON Web Keys on shutdown, and authenticates users in a very silly way.
You have been warned.
dmjwk takes only a single argument --version (or just version), which
causes it to print the version information and exit:
dmjwk --version
dmjwk version v0.1.0 (0903349)Use Go to compile and install from source:
go install github.com/theory/dmjwk@latestFetch the Docker image to run it locally:
docker pull ghcr.io/theory/dmjwkInstall the universal binary installer (ubi) and use it to install
dmjwk and many other tools:
ubi --project theory/dmjwk --in ~/binStart dmjwk with a self-signed certificate:
env DMJWK_CONFIG_DIR="$(pwd)" DMJWK_PORT=4433 dmjwkOr in Docker:
docker run -d -p 4433:443 --name dmjwk --volume .:/etc/dmjwk ghcr.io/theory/dmjwkEither command should create ca.pem in the current directory. Use it with
your favorite HTTP client to make validated requests. For example, to fetch
the JWK set:
curl --cacert ca.pem https://localhost:4433/.well-known/jwks.jsonTo fetch a JWT signed by the first key in the JWK set, make an
application/x-www-form-urlencoded POST with the required grant_type,
username, and password fields:
form='grant_type=password&username=kamala&password=a2FtYWxh'
curl --cacert ca.pem -d "$form" https://localhost:4433/authorizationUse the access_token field in the returned JSON as a Bearer token to reflect
a request to /resource:
tok=$(curl -s --cacert ca.pem -d "$form" https://localhost:4433/authorization | jq -r .access_token)
curl --cacert ca.pem -H "Authorization: Bearer $tok" https://localhost:4433/resource -d '
HELLO WORLD
'Or use the Bearer token for any request to a service that uses
https://localhost:4433/.well-known/jwks.json to authenticate requests.
See openapi.json for the complete documentation. Here's a summary.
curl --cacert ca.pem https://localhost:4433/openapi.jsonReturns openapi.json. Requires no authentication.
curl --cacert ca.pem https://localhost:4433/.well-known/jwks.jsonReturns the JSON Web Key set generated when the service started. Example response:
{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"x": "Ld98DHMIIanlpdOhYf-8GljNHnxHW_i6Bq0iltw9J98",
"y": "xxyRGhCFIjdQFD-TAs-y6uf18wsPvkq8wH_FsGY1GyU"
}
]
}form='grant_type=password&username=kamala&password=a2FtYWxh'
curl --cacert ca.pem -d "$form" https://localhost:4433/authorizationResource Owner Password Credentials Grant API. Client ID basic auth header optional. Validates password authorization for a given username and returns an OAuth 2.0 Access Token with optional RFC 8693 claims. Example successful response:
{
"access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6IiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJrYW1hbGEiLCJleHAiOjE3NjY5NDQyNzcsImlhdCI6MTc2Njk0MDY3NywianRpIjoiZ3hhNnNib292aTg5dSJ9.04efdORHDA3GIPMnWErMPy4mXXsBfbnMJlzqZsxGVEc2cRvEWI0Mt_IqHDK4RYK_14BCEu2nTMiEPtgwC2IZ5A",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read"
}Returns an application/json response with http code 400 on authorization
failure:
curl --cacert ca.pem -sd "username=hi" https://localhost:4433/authorization{
"error": "invalid_request",
"error_description": "missing grant_type"
}grant_type: Type of grant. Must be "password". Required.
username: Username to authorize. May be any string. Will be returned in
the JWT sub field. Required.
password: Password. Authentication succeeds base64-encoded username
without trailing equal signs. Required.
scope: Value to include in the scope field of the JWT and the
response. Specify multiple times for multiple audiences. Optional.
client_id: Value to include in the client_id field of the JWT. Used
only when no for requests without Basic Authentication. Optional.
kid: The ID of the Key to use to sign the JWT. Must be one of the values
specified by DMJWK_KIDS. Optional.
iss: Value to include in the the JWT iss field. Overrides the value
specified by DMJWK_ISSUER. Optional.
aud: Value to include in the the JWT aud field. Specify multiple times
for multiple audiences. Overrides the value specified by
DMJWK_AUDIENCE. Optional.
form='grant_type=password&username=kamala&password=a2FtYWxh'
tok=$(curl -s --cacert ca.pem -d "$form" https://localhost:4433/authorization | jq -r .access_token)
curl --cacert ca.pem -H "Authorization: Bearer $tok" https://localhost:4433/resource -d '
HELLO WORLD
'
HELLO WORLD
Simple OAuth 2 Bearer Token resource API. Submit a JWT returned by
/authorization as a Bearer token and the API will
reflect back the content type and body of the request. If the request contains
no content-type, the returned type will be application/octet-stream.
Returns an application/json response with http code 401 and an
WWW-Authenticate header on authentication failure:
curl --cacert ca.pem -H "Authorization: Bearer NONE" https://localhost:4433/resource -d 'Hi'{
"error": "invalid_token",
"error_description": "token is malformed: token contains an invalid number of segments"
}If dmjwk starts with DMJWK_ISSUER configured, validation will
require the token's iss field to contain this value. And if dmjwk starts
with DMJWK_AUDIENCE configured, validation will require the
token's aud field to contain at least one of its values. JWTs generated by
the authorization API will contain the values of these
configurations unless overridden by its iss and/or aud form parameters.
Otherwise it must be configured through the use of the following environment variables:
Paths relative to DMJWK_CONFIG_DIR for the TLS public/private key pairs the
server will use to identify itself. The files must contain PEM encoded data.
The certificate file may contain intermediate certificates following the leaf
certificate to form a certificate chain.
If no DMJWK_KEY_PATH is provided, dmjwk will create a self-signed
certificate.
Path to the configuration directory. Defaults to /etc/dmjwk. If no
DMJWK_KEY_PATH is specified, dmjwk will create a self-signed certificate and
write a PEM-formatted CA bundle file named ca.pem into this directory. Use
this file to make verified requests to the dmjwk server, for example via the
curl --cacert option or CURL_CA_BUNDLE environment variable.
Comma-delimited list of host names to include in the self signed certificate
in addition to the IP addresses 127.0.0.1, 0.0.0.0, the IPv6 loopback
address, and variants of localhost. Not used when DMJWK_KEY_PATH and
DMJWK_CERT_PATH provide a certificate.
The port on which dmjwk will listen. Defaults to 443.
Comma-delimited list of key identifiers. dmjwk will create a JSON Web Key
(JWK) for each. If none is provided it will create a single key with no KID.
Otherwise, the first ID in the list will identify the default key used to sign
JSON Web Tokens (JWTs) returned by the /authorization endpoint.
Name to use for the iss field of JSON Web Tokens (JWTs) returned by the
/authorization endpoint.
Comma-delimited list of values fill the aud field of JSON Web Tokens (JWTs)
returned by the /authorization endpoint.
Amount of time assigned to the exp field of JSON Web Tokens (JWTs) returned
by the /authorization endpoint. Specif as a duration string, a possibly
signed sequence of decimal numbers, each with optional fraction and a unit
suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us"
(or "µs"), "ms", "s", "m", "h". Defaults to "1h".