I don’t know if you actually got a good answer here. Our setup is very similar React → Absinthe/Phoenix.
We set an httpOnly cookie like this and as someone else noted, it gets sent with the HTTP requests.
router.ex
scope "/api/graphql" do
pipe_through [
:graphql,
:api_version,
:api_auth,
:set_sentry_context,
:inject_graphql_context
]
forward(
"/",
Absinthe.Plug,
schema: OurAppWeb.Graphql.Schema,
analyze_complexity: true,
max_complexity: 1000,
pipeline: {OurAppWeb.Grapqhl.Schema.Pipeline, :pipeline},
before_send: {OurAppWeb.Authentication.AbsintheCookieResponse, :absinthe_before_send}
)
end
absinthe_cookie_response.ex
defmodule OurAppWeb.Authentication.AbsintheCookieResponse do
# Used by router like https://hexdocs.pm/absinthe_plug/Absinthe.Plug.html#module-before-send
def absinthe_before_send(conn, %Absinthe.Blueprint{} = blueprint) do
if Map.has_key?(blueprint.execution.context, :access_token) do
access_token = blueprint.execution.context.access_token
Plug.Conn.put_resp_cookie(
conn,
# This name matches what is expected by Guardian.Plug.VerifyCookie
"guardian_default_token",
access_token || "",
# Setting expires in the past is the official way to delete a cookie
# https://stackoverflow.com/a/53573622
max_age: if(access_token, do: 25 * 365 * 24 * 60 * 60, else: -100_000),
http_only: true,
secure: Application.get_env(:our_app, :cookie_secure)
)
else
conn
end
end
def absinthe_before_send(conn, _) do
conn
end
end
in schema somewhere:
object :user_mutations do
field :login_with_password, type: :login_with_password_payload do
arg :input, non_null(:login_with_password_input)
resolve &UserResolver.login_with_password/2
# Put the user and token in the context
middleware fn res, _ ->
with %{value: %{user: user, token: token}} <- res do
next_context =
res.context
|> Map.put(:current_user, user)
|> Map.put(:access_token, token)
%{res | context: next_context}
end
end
end
We have a different token for websockets for subscriptions, which gets created by a simple graphql HTTP call, then passed on the websocket creation.