joken-elixir / joken_jwks

A Joken 2 hook for fetching the signer from a public JWKS url
Apache License 2.0
29 stars 24 forks source link

ETS table does not exist (sometimes) #46

Closed Sgoettschkes closed 9 months ago

Sgoettschkes commented 10 months ago

We use joken and joken_jwks in our application and it works very well.

Our usage is very basic (I believe). We have the following Token implementation:

defmodule App.Accounts.Tokens.Google do
  @moduledoc false
  use Joken.Config, default_signer: nil

  @iss "https://accounts.google.com"

  defp aud, do: Application.fetch_env!(:elixir_auth_google, :client_id)

  add_hook(JokenJwks, strategy: App.Accounts.Tokens.Strategy)

  @impl Joken.Config
  def token_config do
    default_claims()
    |> add_claim("iss", nil, &(&1 == @iss))
    |> add_claim("aud", nil, &(&1 == aud()))
  end
end

And the following strategy:

defmodule App.Accounts.Tokens.Strategy do
  @moduledoc false
  use JokenJwks.DefaultStrategyTemplate

  def init_opts(opts) do
    url = "https://www.googleapis.com/oauth2/v3/certs"
    Keyword.merge(opts, jwks_url: url)
  end
end

We face some issues with our app refusing to start (in staging, mostly) with the following error message:

[error] Task #PID<0.845.0> started from App.Supervisor terminating
** (ArgumentError) errors were found at the given arguments:

  * 1st argument: the table identifier does not refer to an existing ETS table

    (stdlib 5.0) :ets.insert(App.Accounts.Tokens.Strategy.EtsCache, {:signers, %{PRUNED}})
    (app 0.1.0) lib/app/accounts/tokens/strategy.ex:3: App.Accounts.Tokens.Strategy.EtsCache.put_signers/1
    (app 0.1.0) lib/app/accounts/tokens/strategy.ex:3: App.Accounts.Tokens.Strategy.fetch_signers/2
    (elixir 1.15.4) lib/task/supervised.ex:101: Task.Supervised.invoke_mfa/2
Function: #Function<1.47344484/0 in App.Accounts.Tokens.Strategy.start_fetch_signers/2>
    Args: []

It seemed like a race condition because it worked most of the time. We were not able to figure out what went wrong and diving into the joken_jwks code, it seems strange that the ETS table would not be created because we'd expect the process to fail earlier when setting the counter to 0.

After some more investigating, the problem seems to be related to the compilation step, not the runtime. The reason we suspect this is that a build that throws the error above does it every time it's started and a build that does not throw on the first start does not throw at all. Locally it's the same, as soon as the app throws the error at startup each mix phx.server will throw the error. Recompiling the app will solve this, but changing unrelated files (which only trigger a partial recompile) does not.

victorolinasc commented 9 months ago

Hi @Sgoettschkes ! I will move your comment to #40 which seems to be exactly the same issue!

I will tackle this next. I have already merged the change to a GenServer from a Task which SHOULD have fixed the main issue (since we now initialize this on a callback).

Thanks for raising this!