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!