Liking cljdoc? Tell your friends :D

Verifying with Remote JWKS

jose.jwks wraps Nimbus key sources. A source can be remote and cached. It can also be local and in-memory.

(require '[jose.jwk :as jwk]
         '[jose.jwks :as jwks]
         '[jose.jws :as jws]
         '[jose.jwt :as jwt])

Remote sources

(def source
  (jwks/remote-source "https://www.googleapis.com/oauth2/v3/certs"
                      {:cache-ttl-ms 300000
                       :cache-refresh-ms 15000
                       :connect-timeout-ms 5000
                       :read-timeout-ms 5000
                       :rate-limit-ms 30000}))

Options:

OptionMeaning
:cache-ttl-msCache time to live in milliseconds.
:cache-refresh-msCache refresh timeout in milliseconds.
:connect-timeout-msHTTP connect timeout in milliseconds.
:read-timeout-msHTTP read timeout in milliseconds.
:rate-limit-msMinimum interval for Nimbus rate limiting.

All options are optional. Without options, Nimbus uses its defaults. The remote source from Nimbus already caches keys.

Invalid URLs throw ex-info with {:jose/error :invalid-url}. jwks/get-keys throws {:jose/error :key-source-failure} for a remote retrieval failure.

Local sources

(def rsa-key
  (jwk/generate :rsa {:kid "rsa-1" :use :sig :alg :rs256}))

(def local
  (jwks/local-source [(jwk/public-jwk rsa-key)]))

jwks/local-source accepts a vector of JWKs. It also accepts a JWK set value accepted by jwk/parse-set.

Selecting keys

(jwks/get-keys local {:kid "rsa-1"})
(jwks/get-keys local {:kty :rsa :use :sig :alg :rs256})
(jwks/find-key local "rsa-1")

Matcher options for jwks/get-keys:

OptionValues
:kidKey ID string.
:kty:rsa, :ec, :okp, or :oct.
:use:sig or :enc.
:algAlgorithm keyword, string, or Nimbus Algorithm.

jwks/get-keys returns a vector. jwks/find-key returns the first matching key for a key ID, or nil.

Verifying JWS or JWT

(def compact-jws
  (jws/sign rsa-key "payload" {:alg :rs256 :kid "rsa-1"}))

(jws/verify-with-jwks local compact-jws)
;; => {:payload "payload", :payload-bytes ..., :header ...}

(def compact-jwt
  (jwt/sign rsa-key
            {:sub "alice" :iss "https://issuer.example"}
            {:alg :rs256 :kid "rsa-1" :expires-in 3600}))

(jwt/verify-with-jwks local compact-jwt {:iss "https://issuer.example"})
;; => verified claims map

jws/verify-with-jwks and jwt/verify-with-jwks select a key from the compact object header kid and alg. They then call the normal verifier.

Key selection errors:

:jose/errorCause
:key-not-foundNo key matches the header kid and alg.
:ambiguous-keyThe compact object has no kid and more than one key matches alg.

jose-clj chooses the verifier from the selected JWK key type. It does not trust the algorithm in the compact object. An HS256 forgery over an RSA public key is rejected because the selected RSA JWK is verified with an RSA verifier, not a MAC verifier.

Integration tests

The repository includes a ^:integration test that reads the Google certificate JWKS:

(jwks/remote-source "https://www.googleapis.com/oauth2/v3/certs")

Kaocha skips it by default through tests.edn:

:skip-meta [:integration]

Use remote-source examples only when the test environment has network access.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close