Liking cljdoc? Tell your friends :D

funcade

creates, manages and refreshes jwt tokens

<! release <! clojars

make them tokens

=> (require '[funcade.core :as f])

=> (def conf {:client-id "planet-earth"
              :scope "solar-system"
              :access-token-url "https://milky-way-galaxy/token.oauth2"
              :client-secret "super-hexidecimal-secret"})

optional config properties:

namedefaultdescription
:token-headers{:Content-Type "application/x-www-form-urlencoded"}headers passed to aquire the token
:grant-type"client_credentials"oauth 2.0 grant type
:refresh-percent10when less than % of time between expires-at and issued-at remains, refreshes the token
=> (def token-repo (f/wake-token-master :serpens conf))

=> (f/current-token token-repo)
;; "eyJhbGci...dc22w"
user=> (f/stop token-repo)
true

group many sources

=> (def sources {:mars {:client-id "..."
                        :client-secret "..."
                        :access-token-url "..."
                        :scope "..."}
                 :asgard {:client-id "..."
                          :client-secret "..."
                          :access-token-url "..."
                          :scope "..."}})

=> (def jwt (f/wake-token-masters sources))

creates two token masters:

=> jwt
;; {:mars #object[funcade.core.TokenMaster"],
;;  :asgard #object[funcade.core.TokenMaster"]}

=> (-> jwt :mars f/current-token)
;; "eyJhbGci...dc22w"

=> (-> jwt :asgard f/current-token)
;; "eyJhbRkv...id95p"

use key sets (JWKS)

=> (require '[funcade.jwks :as jk])

=> (jk/jwks->keys "https://foo.com/bar/jwks")
{"key-for-cert-one" #object[bouncycastle..BCRSAPublicKey "RSA Public Key [e7:ec:...]
 "key-for-cert-two" #object[bouncycastle..BCRSAPublicKey "RSA Public Key [f1:25:...]
 "key-for-cert-three" #object[bouncycastle..BCRSAPublicKey "RSA Public Key [b4:39:...]}

keys are looked up by token's kid:

=> (def keys (jk/jwks->keys "https://foo.com/bar/jwks"))

=> (def token "eyJhbGciOiJSUzI1Ni...")
#'user/token

=> (jk/find-token-key keys token)
#object[org.bouncycastle..BCRSAPublicKey "RSA Public Key [f1:25:]

using middleware

funcade has middleware and helpers to use auth requests protected behind JWT tokens with various scopes.

=> (require '[reitit.ring :as ring])
=> (require '[funcade.middleware.reitit :as fun])

=> (def config {:jwk {:uri "https://milky-way-galaxy/ext/jwtsigningcert/jwks"})

=> (def app
      (ring/ring-handler
        (ring/router
          ["/ping" {:get {:scope :my-scope
                          :handler (fn [_]
                                     {:status 200
                                      :body "success"})}}]
          {:data {:middleware [(fun/wrap-jwt-authentication config})
                               fun/scope-middleware]}})))

valid request:

=> (def token "eyJhbGci...dc22w")

=> (app {:request-method :get :uri "/ping" :headers {:authorization (str "Bearer " token)}})
;; {:status 200, :body "success"}

invalid/missing token:

=> (app {:request-method :get :uri "/ping"}})
;; {:status 401, :body {:error "invalid authorization header", :message "access to /ping is not authorized"}}

invalid scope:

=> (def token "eyJhbGci...dc22w")

=> (app {:request-method :get :uri "/ping" :headers {:authorization (str "Bearer " token)}})
;; {:status 401, :body {:message "missing required scope", :required :my-scope, :scopes (:not-my-scope)}}

Java API

import funcade.core.TokenMaster;
import tolitius.Funcade;
var config  = Map.of("client-id", clientId,
                     "client-secret", clientSecret,
                     "access-token-url", accessTokenUri,
                     "username", username,
                     "password", password,
                     "grant-type", grantType);

var tokenMaster = Funcade.wakeTokenMaster("asgard", config);

and then whenever you need a token:

var token = Funcade.currentToken(tokenMaster);

license

copyright © 2022 @shvetsm / tolitius

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

Can you improve this documentation? These fine people already did:
anatoly, Mark Shvets, Anatoly & James Kent
Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close