Reputation: 8444
In my Phoenix app, I am using Guardian and GuardianDb for user authorization. Initially, I was only using Guardian and everything with the auth process was working just fine. However, after adding GuardianDb to the mix (for token storage), token records are being created correctly, but I'm getting a no case clause matching
error that's throwing a wrench into the works and I cannot seem to figure out how to get around it. Here's how it's all going down...
First off, from mix.exs
:
{:guardian, "~> 0.14"},
{:guardian_db, "~> 0.8.0"},
and, as specified in the docs, config.exs
:
config :guardian, Guardian,
hooks: GuardianDb,
issuer: "MyApp",
ttl: {30, :days},
verify_issuer: true,
serializer: MyApp.GuardianSerializer
config :guardian_db, GuardianDb,
repo: MyApp.Repo,
schema_name: "guardian_tokens"
The error is raised during the create
action in session_controller.ex
:
def create(conn, %{"person" => person_params}) do
case authenticate(person_params) do
{:ok, person} ->
new_conn = Guardian.Plug.api_sign_in(conn, person, :access)
jwt = Guardian.Plug.current_token(new_conn)
json new_conn, %{status: "ok", data: person, meta: %{token: jwt}}
:error ->
json(conn |> put_status(401), %{status: "error", message: "Invalid credentials"})
end
end
When I try to call on this action, the desired record is created in the database - however, I get the following error (backslashes added for tidy formatting):
(CaseClauseError) no case clause matching:
{:ok, {%MyApp.Person{__meta__: #Ecto.Schema.Metadata<:loaded, "people">, \
deleted_at: nil, email: "[email protected]", first_name: "FirstName", \
id: "people:Jz3bIt54283NvZb", inserted_at: ~N[2017-05-01 18:02:17.750603], \
last_name: "LastName", password: nil, updated_at: ~N[2017-05-01 18:02:17.750612]}, \
:access, %{"aud" => "people:Jz3bIt54283NvZb", "exp" => 1496441175, \
"iat" => 1493849175, "iss" => "MyApp", \
"jti" => "248e62ed-a2a2-4a0a-9e08-eae0190516c6", "pem" => %{}, \
"sub" => "Person:people:Jz3bIt54283NvZb", "typ" => "access"}, \
"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJQZXJzb246cGVvcGxlOkp6M2JJdEpnTzU4M052WmIiLCJleHAiOjE0OTY0NDExNzUsImlhdCI6MTQ5Mzg0OTE3NSwiaXNzIjoiUGhvZW5peEJhY2tlbmQiLCJqdGkiOiIyNDhlNjJkZC1hMmEyLTRhMGEtOWYwOC1lYWUwMTkwNTE2YzYiLCJwZW0iOnt9LCJzdWIiOiJQZXJzb246cGVvcGxlOkp6M2JJdEpnTzU4M052WmIiLCJ0eXAiOiJhY2Nlc3MifQ.DliX044wFmKpCrawuH3W_DoCya2VYAdrxZfwWEGWtW_ymDxXmQgV6XL3bHRkPKhSHziaFQFMvHIGS9yKtBfTkg"}}
With the trace:
lib/guardian.ex:100: Guardian.encode_from_hooked/1
lib/guardian/plug.ex:178: Guardian.Plug.api_sign_in/4
(phoenix_backend) web/controllers/session_controller.ex:9: MyApp.SessionController.create/2
The first two lines from that trace are from the dependencies, and the third line refers to Guardian.Plug.api_sign_in(conn, person, :access)
from the controller above.
Now before I added GuardianDb, this controller action worked perfectly, but it seems now that the process is getting hung up in one of the hooks in the dependencies, and I'm not sure how to proceed.
For reference, the first line in the trace points to call_after_encode_and_sign_hook
in the function encode_from_hooked
:
defp encode_from_hooked({:ok, {resource, type, claims_from_hook}}) do
{:ok, jwt} = encode_claims(claims_from_hook)
case call_after_encode_and_sign_hook( # THIS IS LINE 100
resource,
type,
claims_from_hook, jwt
) do
:ok -> {:ok, jwt, claims_from_hook}
{:error, reason} -> {:error, reason}
end
end
and the second line in the trace points to encode_and_sign
in the api_sign_in
function:
def api_sign_in(conn, object, type, new_claims) do
the_key = Map.get(new_claims, :key, :default)
new_claims = Map.delete(new_claims, :key)
case Guardian.encode_and_sign(object, type, new_claims) do # THIS IS LINE 178
{:ok, jwt, full_claims} ->
conn
|> set_current_resource(object, the_key)
|> set_claims({:ok, full_claims}, the_key)
|> set_current_token(jwt, the_key)
|> Guardian.hooks_module.after_sign_in(the_key)
{:error, reason} ->
set_claims(conn, {:error, reason}, the_key)
end
end
Again, I just want to emphasize that the controller action worked perfectly before incorporating GuardianDb. Now that I've added GuardianDb, the record is created correctly in the database but new_conn
is not correctly defined.
I know there's a lot of code here, but I'm stumped - if anyone can shed some light, muy bueno.
Upvotes: 0
Views: 1338
Reputation: 8444
Ok well I did figure out a solution, though I'm reluctant to implement it in my app since this is inside of a dep...
All I had to do was adjust the :ok
case
clause in encode_from_hooked
so that the function reads like so:
defp encode_from_hooked({:ok, {resource, type, claims_from_hook}}) do
{:ok, jwt} = encode_claims(claims_from_hook)
case call_after_encode_and_sign_hook(
resource,
type,
claims_from_hook, jwt
) do
{:ok, _} -> {:ok, jwt, claims_from_hook}
:ok -> {:ok, jwt, claims_from_hook}
{:error, reason} -> {:error, reason}
end
end
Just needed an extra case for when a tuple is returned with :ok
.
Upvotes: 0