lib/public_key_store.ex

defmodule FirebaseJwt.PublicKeyStore do
  @googleCertificateUrl "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"

  use GenServer
  require Logger

  def start_link([]) do
    GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
  end

  def init(init_arg) do
    {:ok, init_arg}
  end

  def fetch_firebase_keys() do
    response = HTTPoison.get!(@googleCertificateUrl)
    {_, expire} = Enum.find(response.headers, fn {k, _} -> String.downcase(k) == "expires" end)

    store(:public_keys, Jason.decode!(response.body))
    store(:expire, Timex.parse!(expire, "{RFC1123}"))
    Application.get_env(:firebase_jwt, :debug_log) && Logger.debug("#{__MODULE__} public keys updated.")
  end

  def store(key, value) do
    GenServer.cast(__MODULE__, {:store, key, value})
  end

  def get(key) do
    GenServer.call(__MODULE__, {:lookup, key})
  end

  def get_public_key(key_id) do
    case get(:public_keys) |> Map.get(key_id) do
      nil ->
        fetch_firebase_keys()
        get(:public_keys) |> Map.get(key_id)

      public_key ->
        public_key
    end
  end

  def handle_cast({:store, key, value}, state) do
    {:noreply, state |> Map.put(key, value)}
  end

  def handle_call({:lookup, key}, _from, state) do
    {:reply, state[key], state}
  end
end