I have been learning Elixir for the past 7 days and honestly I am in love with the language.
There has been one issue that is bugging me for straight 2 days and I can’t seem to fix it, and since I am new into Elixir I am not even trying to modify libraries myself.
Here is the issue, I am using guardian 2.3.2, guardian_db 3.0.0 and guardian_redis 0.2.0. Since when calling database with guardian_db everytime just to check validation of JWT is expensive, I decided to implement it with redis, when turns out there is library called guardian_redis. But here is the issue. Whenever I add it to my project and try to login I get this error:
[error] ** (FunctionClauseError) no function clause matching in someprojectBackendElixirWeb.Router.handle_errors/2
(someproject_backend_elixir 0.1.0) lib/someproject_backend_elixir_web/router.ex:5: someprojectBackendElixirWeb.Router.handle_errors(%Plug.Conn{adapter: {Bandit.Adapter, :...}, assigns: %{}, body_params: %{"email" => "someemail@gmail.com", "hashed_password" => "password"}, cookies: %{"_someproject_backend_elixir_key" => "SFMyNTY.g3QAAAABbQAAAAphY2NvdW50X2lkbQAAACQyYWRlZTRlYy1jZTIyLTQ2MGUtYTJiZi00YzJmMmExMGU2MWU.dzBeNhacCXQwwTnAWqWSO01h0Wj2LN5GvusHC2AmkSU"}, halted: false, host: "localhost", method: "POST", owner: #PID<0.649.0>, params: %{"email" => "someemail@gmail.com", "hashed_password" => "password"}, path_info: ["api", "accounts", "login"], path_params: %{}, port: 4000, private: %{:phoenix_view => %{"html" => someprojectBackendElixirWeb.AccountHTML, "json" => someprojectBackendElixirWeb.AccountJSON}, someprojectBackendElixirWeb.Router => [], :phoenix_endpoint => someprojectBackendElixirWeb.Endpoint, :plug_session_fetch => :done, :plug_session => %{"account_id" => "2adee4ec-ce22-460e-a2bf-4c2f2a10e61e"}, :before_send => [#Function<0.9035112/1 in Plug.Session.before_send/2>, #Function<0.106864063/1 in Plug.Telemetry.call/2>], :phoenix_router => someprojectBackendElixirWeb.Router, :phoenix_action => :login, :phoenix_layout => %{"html" => {someprojectBackendElixirWeb.Layouts, :app}}, :phoenix_controller => someprojectBackendElixirWeb.AccountController, :phoenix_format => "json"}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %{"_someproject_backend_elixir_key" => "SFMyNTY.g3QAAAABbQAAAAphY2NvdW50X2lkbQAAACQyYWRlZTRlYy1jZTIyLTQ2MGUtYTJiZi00YzJmMmExMGU2MWU.dzBeNhacCXQwwTnAWqWSO01h0Wj2LN5GvusHC2AmkSU"}, req_headers: [{"cookie", "_someproject_backend_elixir_key=SFMyNTY.g3QAAAABbQAAAAphY2NvdW50X2lkbQAAACQyYWRlZTRlYy1jZTIyLTQ2MGUtYTJiZi00YzJmMmExMGU2MWU.dzBeNhacCXQwwTnAWqWSO01h0Wj2LN5GvusHC2AmkSU"}, {"content-length", "84"}, {"connection", "keep-alive"}, {"accept-encoding", "gzip, deflate, br"}, {"host", "localhost:4000"}, {"postman-token", "6939017f-2db8-4b02-9d43-aa4f6ab93a12"}, {"accept", "*/*"}, {"user-agent", "PostmanRuntime/7.41.2"}, {"content-type", "application/json"}], request_path: "/api/accounts/login", resp_body: nil, resp_cookies: %{}, resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}, {"x-request-id", "F_HQOB_eYIC1Qd8AAACN"}], scheme: :http, script_name: [], secret_key_base: :..., state: :unset, status: 500}, %{reason: %MatchError{term: {:error, :token_storage_failure}}, stack: [{someprojectBackendElixirWeb.Auth.Guardian, :create_token, 1, [file: ~c"lib/someproject_backend_elixir_web/auth/guardian.ex", line: 41]}, {someprojectBackendElixirWeb.AccountController, :login, 2, [file: ~c"lib/someproject_backend_elixir_web/controllers/account_controller.ex", line: 37]}, {someprojectBackendElixirWeb.AccountController, :action, 2, [file: ~c"lib/someproject_backend_elixir_web/controllers/account_controller.ex", line: 1]}, {someprojectBackendElixirWeb.AccountController, :phoenix_controller_pipeline, 2, [file: ~c"lib/someproject_backend_elixir_web/controllers/account_controller.ex", line: 1]}, {Phoenix.Router, :__call__, 5, [file: ~c"lib/phoenix/router.ex", line: 484]}, {someprojectBackendElixirWeb.Router, :call, 2, [file: ~c"deps/plug/lib/plug/error_handler.ex", line: 80]}, {someprojectBackendElixirWeb.Endpoint, :plug_builder_call, 2, [file: ~c"lib/someproject_backend_elixir_web/endpoint.ex", line: 1]}, {someprojectBackendElixirWeb.Endpoint, :"call (overridable 3)", 2, [file: ~c"deps/plug/lib/plug/debugger.ex", line: 136]}, {someprojectBackendElixirWeb.Endpoint, :call, 2, [file: ~c"lib/someproject_backend_elixir_web/endpoint.ex", line: 1]}, {Phoenix.Endpoint.SyncCodeReloadPlug, :do_call, 4, [file: ~c"lib/phoenix/endpoint/sync_code_reload_plug.ex", line: 22]}, {Bandit.Pipeline, :call_plug!, 2, [file: ~c"lib/bandit/pipeline.ex", line: 124]}, {Bandit.Pipeline, :run, 4, [file: ~c"lib/bandit/pipeline.ex", line: 36]}, {Bandit.HTTP1.Handler, :handle_data, 3, [file: ~c"lib/bandit/http1/handler.ex", line: 12]}, {Bandit.DelegatingHandler, :handle_data, 3, [file: ~c"lib/bandit/delegating_handler.ex", line: 18]}, {Bandit.DelegatingHandler, :handle_continue, 2, [file: ~c"d:/Stvari/Programiranje/someprojectFinal/someproject_backend_elixir/deps/thousand_island/lib/thousand_island/handler.ex", line: 411]}, {:gen_server, :try_handle_continue, 3, [file: ~c"gen_server.erl", line: 2163]}, {:gen_server, :loop, 7, [file: ~c"gen_server.erl", line: 2072]}, {:proc_lib, :init_p_do_apply, 3, [file: ~c"proc_lib.erl", line: 329]}], kind: :error})
(plug 1.16.1) lib/plug/error_handler.ex:113: Plug.ErrorHandler.__catch__/6
(someproject_backend_elixir 0.1.0) lib/someproject_backend_elixir_web/endpoint.ex:1: someprojectBackendElixirWeb.Endpoint.plug_builder_call/2
(someproject_backend_elixir 0.1.0) deps/plug/lib/plug/debugger.ex:136: someprojectBackendElixirWeb.Endpoint."call (overridable 3)"/2
(someproject_backend_elixir 0.1.0) lib/someproject_backend_elixir_web/endpoint.ex:1: someprojectBackendElixirWeb.Endpoint.call/2
(phoenix 1.7.14) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4
(bandit 1.5.7) lib/bandit/pipeline.ex:124: Bandit.Pipeline.call_plug!/2
(bandit 1.5.7) lib/bandit/pipeline.ex:36: Bandit.Pipeline.run/4
(bandit 1.5.7) lib/bandit/http1/handler.ex:12: Bandit.HTTP1.Handler.handle_data/3
(bandit 1.5.7) lib/bandit/delegating_handler.ex:18: Bandit.DelegatingHandler.handle_data/3
(bandit 1.5.7) d:/Stvari/Programiranje/someprojectFinal/someproject_backend_elixir/deps/thousand_island/lib/thousand_island/handler.ex:411: Bandit.DelegatingHandler.handle_continue/2
(stdlib 6.0.1) gen_server.erl:2163: :gen_server.try_handle_continue/3
(stdlib 6.0.1) gen_server.erl:2072: :gen_server.loop/7
(stdlib 6.0.1) proc_lib.erl:329: :proc_lib.init_p_do_apply/3
Now I don’t really understand why is this happening when I have been following guardian_redis docs and put everything in right place that I need.
In config.exs:
config :guardian, Guardian.DB,
adapter: GuardianRedis.Adapter
config :guardian_redis, :redis,
host: "my upstash redis url is here",
port: 6379,
password: "my upstash redis password is here",
pool_size: 10
And in my application.ex under children I added:
GuardianRedis.Redix
Also it is said that I should first set up Guardian.DB normally like how I would do it and just change whtat they say which I also did and these functions exist as well:
defmodule SomeprojectBackendElixirWeb.Auth.Guardian do
use Guardian, otp_app: :someproject_backend_elixir
alias SomeprojectBackendElixir.Accounts
def subject_for_token(%{id: id}, _claims) do
sub = to_string(id)
{:ok, sub}
end
def subject_for_token(_, _) do
{:error, :no_id_provided}
end
def resource_from_claims(%{"sub" => id}) do
case Accounts.get_account!(id) do
nil -> {:error, :not_found}
resource -> {:ok, resource}
end
end
def resource_from_claims(_claims) do
{:error, :no_id_provided}
end
def authenticate(email, password) do
case Accounts.get_account_by_email(email) do
nil -> {:error, :unauthored}
account ->
case validate_password(password, account.hashed_password) do
true -> create_token(account)
false -> {:error, :unauthorized}
end
end
end
defp validate_password(password, hashed_password) do
Bcrypt.verify_pass(password, hashed_password)
end
defp create_token(account) do
{:ok, token, _claims} = encode_and_sign(account)
{:ok, account, token}
end
def after_encode_and_sign(resource, claims, token, _options) do
with {:ok, _} <- Guardian.DB.after_encode_and_sign(resource, claims["typ"], claims, token) do
{:ok, token}
end
end
def on_verify(claims, token, _options) do
with {:ok, _} <- Guardian.DB.on_verify(claims, token) do
{:ok, claims}
end
end
def on_refresh({old_token, old_claims}, {new_token, new_claims}, _options) do
with {:ok, _, _} <- Guardian.DB.on_refresh({old_token, old_claims}, {new_token, new_claims}) do
{:ok, {old_token, old_claims}, {new_token, new_claims}}
end
end
def on_revoke(claims, token, _options) do
with {:ok, _} <- Guardian.DB.on_revoke(claims, token) do
{:ok, claims}
end
end
end
These are all relevant code blocks, so as you see per documentations everything is done properly but cant seem to fix the error I am getting only when having guardian_redis package and including it.
Thank you in advance