rogerweb

rogerweb

Closure for module configuration?

Hi,

When a user connects to my application via a Phoenix.Socket he/she provides a token (generated by another system) that I would like to verify and validate. I created a Token module to encapsulate all the verification and validation code. It uses Joken to actually do the job and it requires some configuration like creating a signer using a public_key and defining some validation functions for checking the claims (the iss for instance).

These two strings (public key and the expected issuer) are considered configuration and must be provided to the solution via environment variables.

Considering that this configuration part of the flow needs to be executed only once (when the application starts, for instance) and not every time a token is verified, I started wondering what would be the best design, i.e., how to perform the configuration only once and provide a simple verify_and_validate/1 function that takes only the token.

A closure seems to be an option. Example:

  def get_verify_fun(public_key, issuer) do
    config = token_config(issuer)
    signer = Joken.Signer.create("RS256", %{"pem" => public_key})
    fn token -> verify(config, token, signer) end
  end

  defp verify(config, token, signer) do
    with {:ok, claims} <- Joken.verify_and_validate(config, token, signer) do
      check_for_missing_claims(claims, @required_claims)
    end
  end

Now the question is: where to call the get_verify_fun/2 and/or how to make the returned function available to my code in the connect function in the Phoenix.Socket module?

An option is to call the get_verify_fun/2 in my runtime.exs, store the returned function in the application scope using config and use Application.fetch_env! in the socket connect:

Example (runtime.exs):

public_key = get_env("TOKEN_PUBLIC_KEY") |> String.replace("\\n", "\n")
issuer = get_env("TOKEN_ISSUER")
verify = MyApp.Token.get_verify_fun(public_key, issuer)
config :myapp, verify_token: verify

It works but it doesn’t feel right. What do you think?

I know I can fall back to passing the config along with the token on every call to verify but then we would be executing the configuration part over and over. It might be not a big deal in this case if Joken is not doing much, but what if this “configuration” ou “preparation” part of the flow is expensive?

Sorry for the long and not so direct to the point question and let me know if I can clarify anything.

Cheers!

First Post!

kokolegorille

kokolegorille

It looks like You want to cache your function when application start.

Probably using an Agent would be ok.
Or an Ets table (and a GenServer), to speed up think…
Or cachex.
Or a simple file, with :erlang.term_to_binary() and binary_to_term().

Most Liked

hauleth

hauleth

Application.put_env/3 call in Application.start/2 should do.

hauleth

hauleth

Or just application configuration :wink:

Last Post!

rogerweb

rogerweb

Thanks @kokolegorille, @hauleth, @dimitarvp and @gregvaughn for taking the time to read it and contribute.

Application.put_env/3 call in Application.start/2 should do.

Your suggestion is to store the resulting function in the application environment when it starts, right?

Isn’t it what I’m already doing, except that I’m using config in the runtime.exs?

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49266 226
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement