Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about manually refetch the token from public API (e.g. google). #30

Closed
isavita opened this issue Nov 25, 2021 · 4 comments
Closed

Comments

@isavita
Copy link

isavita commented Nov 25, 2021

Thank you, for the very nice library!
I have one question for sync retrying logic.
Is it possible synchronously to refetch the public_key on error?
For example,

  1. There is request with JWT TOKEN generated with the new public key (e.g. with google public key).
  2. On validation of the JWT TOKEN with GoogleToken.verify_and_validate(token) there is error for the token.
  3. What kind of error will get one (2)? How could I refetch sync the token and retry manually on point (2)?
    At the moment if I understand correctly the flow, the new token will be refetch base on how often the time_interval and all request meanwhile with the new token will be failing.
@isavita
Copy link
Author

isavita commented Nov 26, 2021

For the moment I rewrite the poll function to allow manually to send message for refetch.

def poll(opts) do
  interval = opts[:time_interval]

  receive do
    :clean_cache_and_refetch ->
      EtsCache.set_status(:refresh)
      _ = check_fetch(opts)
      poll(opts)
  after
    interval ->
      _ = check_fetch(opts)
      poll(opts)
  end
end

I have in my module for Joken.Config file

defmodule MyApp.MyConfig do
  use Joken.Config

  add_hook(JokenJwks, strategy: MyApp.MyStrategy)

  def verify_and_validate_with_retry(token) do
      data = verify_and_validate(token)
      if {:error, :kid_does_not_match} == data do
        refetch_key()
        verify_and_validate(token)
      else
        data
      end
    end
  
    defp refetch_key do
      {_, pid, :worker, _} =
        MyApp.Supervisor
        |> Supervisor.which_children()
        |> Enum.find(fn child -> elem(child, 0) == MyApp.MyStrategy end)
  
       send(pid, :clean_cache_and_refetch)
    end
  end

I am not sure if there is no better way of doing that.

@lovebes
Copy link
Contributor

lovebes commented May 10, 2022

Question: how were you able to redefine poll() only from the JokenJwks.DefaultStrategyTemplate?
Or did you copy the entire code from JokenJwks.DefaultStrategyTemplate to create the changes?

Your needs are more aligned with a GenServer. That way, you don't need to go too "raw" and use send().
It would be a cleaner approach to do MyApp.MyStrategy.clean_cache_and_refetch().

That way, code is abstracted and nested inside MyApp.MyStrategy, and inner workings are not exposed.

This way you can use a better polling strategy by using GenServer, instead of doing Task-based polling. This is what I need to do after finding a case where Task-based polling fails and keeps restarting, ultimately failing the Supervisor.

This way you can have your custom manual refetcing logic, AND have a more robust polling operation, instead of doing a use Task with a recursive poll() under supervision.

More info here: https://medium.com/@efexen/periodic-tasks-with-elixir-part-2-8aaee425aed0

@victorolinasc
Copy link
Collaborator

@isavita currently there is no sync way of retrying the request manually.

It is important to note that many times this code is executed in a request process. If you don't lock the re-fetching it will probably make many requests until you can sync it locally.

As @lovebes has advised, your use case is different than the current default strategy here. You can implement your own strategy but I will try to add more robust options and scalability to the default approach too.

@lovebes has even proposed PRs that I am taking way too long to merge. I will try to do it ASAP.

@victorolinasc
Copy link
Collaborator

Either way, there is no manual to re-fetch currently so I will close this for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants