alekcz / charmander

A set of libraries to make working with firebase easier in clojure

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add another public method to the core that would only return the correct public key given a token.

lopezvit opened this issue · comments

I decided to create a new issue, just copying from my last commentary from #2 since I think it deserves its own place.

I have also write an issue in #funcool/buddy-auth#89 because it would be awesome that your library could be used directly with buddy-auth, as it would solve all the problems I'm facing authenticating my app with firebase token.
Do you think it could be possible to add another public method that would only return the correct public key given a token?
something like:

(defn- get-token-payload
  "Retrieves payload from token. Payload is used for validation when not unsigning the message"
  [token]
  (let [token-array (str/split token #"\." 3)]
    (json/read-value (base64/decode (pad-token (second token-array))) mapper)))

(defn- return-keys
  "2nd Core library method. Validates token using projectid-regex and checks the times are correct. and returns public key."
  [projectid-regex token opts]
  (let [header  (get-token-header token)
        cert (keys/str->public-key ((keyword (:kid header)) @public-keys))
        unsigned-data (if (keys/public-key? cert) (get-token-payload token) nil)
        validated? (validate-claims unsigned-data)]
    (when validated?
      (verify-domain projectid-regex (format-result unsigned-data))
      cert)))

; public methods

(defn get-secret
  "Public method that makes sure the issuing domain is valid using a regex but return a public key instead of validating
  the signature, to use it with buddy-auth"
  [projectid-regex token]
  (try
    (if (nil? @public-keys)
      (do	(load-public-keys threadpool schedule-public-key-update) (return-keys projectid-regex token))
      (return-keys projectid-regex token))
    (catch Exception _ nil)))

That way it will be easy to create a wrapper around get-secret that would receive only the token.
Important note: My code hasn't been tested, it is just to show what I meant.

@lopezvit could show me how you'd like to be able to use the two libraries together? Or do you have example code of where you'd like to drop in charmander? It'd be easier if I understood how you want it to be used with buddy

Well, the problem is that I would need #funcool/buddy-auth#89 to be solved first.

If, instead of an static value for the parameter secret, I could pass a function that would be executed at execution time, I could create a wrapper of get-secret so the public key would be created dynamically (reloaded from the internet if necessary).

Something like:

(jws-backend {"secret" #(get-secret "<PROJECT_ID_NAME>" %) "options" {:alg :rs256}}) 

I'm on holidays now, that's why I might take some time for me to reply.

Hello, I'm going to close this issue, as I found a workaround that would combine this library with buddy-auth without needing to change any library. Here there is the code that I used. The trick was to change the backend, from Signed JWT backends/jwsto backends/token. That way, the backend doesn't try to verify the signature itself, but gives the opportunity to add a function to the the authentication:

(defn my-authfn
  [request token]
  (log/trace
   (second
    (re-find (re-pattern (str "^" "Token" " (.+)$"))
             (http/-get-header request "authorization"))))
  (log/trace (:uid (charm/validate-token "<YOUR-PROJECT-HERE>" token)))
  (:uid (charm/validate-token "<YOUR-PROJECT-HERE>" token)))

(def backend
  (backends/token
   {:authfn my-authfn}))

In case it could help anybody, do not use https://github.com/magnetcoop/buddy-auth.jwt-oidc library: It might seem that it works, as it allows you to add a URI where to download a JWKS file but firebase's https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com file is not in that format. It took me a lot of time and debug to find out why it wasn't working, but at least it gave me the clue on how to get to this workaround that is actually working.