rogerweb

rogerweb

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!

Showing Posts 1 to 6

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().

hauleth

hauleth

Or just application configuration :wink:

kokolegorille

kokolegorille

But it needs to be dynamic, at least when app starts :slight_smile:

hauleth

hauleth

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

kokolegorille

kokolegorille

Ok, it’s simpler :slight_smile:

rogerweb

rogerweb OP

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?

— All posts loaded —

Where Next? Top

Trending in Questions Top

Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
matt-savvy
Anyone here using Honeybadger? My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of Bandit.HTTPError...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews