Ring middleware for parsing, decoding and verifying a JWS-signed JWT token from the incoming request. (There is no explicit support for JWE currently.)
Built on top of the excellent auth0 JWT library.
Upgrading to 2.4.0 and above: For those upgrading from versions older than
2.4.0
: This version introduced a potentially breaking change to thereject-missing-token?
flag. Instead of defaulting tofalse
it now defaults totrue
. So, if you are not already explicitly setting the field in your configuration, you will need to add an explicit:reject-missing-token? false
.
Once wired into your ring server, the middleware will:
- Search for a JWT token on each incoming request.
- By default, it will parse the bearer token from the
Authorization
HTTP header but this behaviour can be overridden using thefind-token-fn
setting (see usage below).
- By default, it will parse the bearer token from the
- Will add the claims it finds in the token as a clojure map against the
:claims
key on the incoming request. - Add an empty
:claims
map to the request if no token is found. - Respond with a
401
if the JWS signature in the token cannot be verified. - Respond with a
401
if the option map for the matching issuer includes anaudience
setting AND there is aaud
claim included on the incoming token AND those two values do not match (case-sensitively). - Respond with a
401
if the token has expired (i.e. the exp claim indicates a time in the past).- A leeway can be specified for this check with the
leeway-seconds
setting (see usage below).
- A leeway can be specified for this check with the
- Respond with a
401
if the token will only be active in the future (i.e. the nbf claim indicates a time in the future)- As for
exp
, theleeway-seconds
setting can be used to introduce a leeway on this check.
- As for
(require '[ring.middleware.jwt :as jwt])
(defn handler [request]
(response {:foo "bar"}))
(jwt/wrap-jwt handler {:issuers {"https://some/issuer" {:alg :HS256
:secret "asecret"}
"https://another/issuer" {:alg :RS256
:audience "myapi"
:jwk-endpoint "https://some/jwks/endpoint"}
:no-issuer {:alg :HS256
:secret "anothersecret"}}})
Options:
:issuers
(mandatory): A map of issuer->cryptographic algorithm configuration. When receiving a JWT token, the middleware will pull the issuer from theiss
claim and use it to lookup the appropriate algorithm in the middleware configuration to verify the JWT. (So, theiss
claim is implicitly only "trusted" if verification succeeds.)- Optionally, you may include a
:no-issuer
key in the map of issuers - this value will be used if noiss
claim is found in the incoming token.
- Optionally, you may include a
:find-token-fn
(optional): A single-argument function that will be used to pull the (encoded) token from the request map. If unspecified the token will be sought from the bearer token given in theAuthorization
header (i.e. anAuthorization
HTTP header of the form "Bearer TOKEN"):reject-missing-token?
(optional): A flag indicating whether a request missing a JWT token will be rejected with a401
response. Default istrue
. If set tofalse
a missing token will cause authentication to be skipped - and so it is then the responsibility of your service code to determine whether incoming requests missing a token should be rejected or not.:ignore-paths
(optional): set of paths for which the JWT middleware should be ignored. For requests including a:uri
that matches one of the configured paths, the JWT middleware will be skipped.
Depending upon the cryptographic algorithm, a different map of options will be required. Note that, at the point your ring middleware is wired up, ring-jwt will throw an error if it detects that the given options are invalid.
Currently the following JWA algorithms are supported for the purposes of JWS:
Algorithm | Options |
---|---|
ECDSA using P-256 and SHA-256 | {:alg :ES256 :public-key public-key} [1] |
RSASSA-PKCS-v1_5 using SHA-256 | {:alg :RS256 :public-key public-key} [1] |
{:alg :RS256 :jwk-endpoint "https://your/jwk/endpoint"} [2] |
|
HMAC using SHA-256 | {:alg :HS256 :secret "your-secret"} |
- [1]
public-key
is of typejava.security.PublicKey
. - [2] Note that the content from that JWK endpoint is cached internally for up to 10 minutes using the Auth0 GuavaCachedJwkProvider
Additional headers to be sent to the JWK endpoint in the request can be included with a
jwk-headers
map.
Additionally, the following options are supported for all issuers:
leeway-seconds
: The number of seconds leeway to give when verifying the expiry/active from claims of the token (i.e. theexp
andnbf
claims).
Keys for use with Integrant or Duct are available in kelveden/duct.middleware.ring-jwt.
- JSON Web Tokens - JWT Specification
- JSON Web Signatures - JWS Specification
- JSON Web Algorithms - JWA Specification
- JSON Web Keys - JWK Specification
- jwt.io
Distributed under the Eclipse Public License, the same as Clojure.