defmodule ToweropsWeb.Plugs.GraphQLAuthTest do use ToweropsWeb.ConnCase, async: true import Towerops.AccountsFixtures import Towerops.OrganizationsFixtures alias Towerops.ApiTokens alias Towerops.MobileSessions alias ToweropsWeb.Plugs.GraphQLAuth describe "init/1" do test "returns options unchanged" do assert GraphQLAuth.init([]) == [] end end describe "call/2 with API token (towerops_ prefix)" do setup do user = user_fixture() organization = organization_fixture(user.id) {:ok, {_token, raw_token}} = ApiTokens.create_api_token(%{ organization_id: organization.id, user_id: user.id, name: "GraphQL Auth Test Token" }) %{user: user, organization: organization, raw_token: raw_token} end test "authenticates and sets org_id + user", %{ conn: conn, raw_token: raw_token, organization: organization, user: user } do conn = conn |> put_req_header("authorization", "Bearer #{raw_token}") |> GraphQLAuth.call([]) refute conn.halted assert conn.assigns.current_organization_id == organization.id assert conn.assigns.current_user.id == user.id end test "returns 401 for expired API token", %{conn: conn, organization: organization, user: user} do expires_at = DateTime.add(DateTime.utc_now(), -1, :day) {:ok, {_token, raw_token}} = ApiTokens.create_api_token(%{ organization_id: organization.id, user_id: user.id, name: "Expired Token", expires_at: expires_at }) conn = conn |> put_req_header("authorization", "Bearer #{raw_token}") |> GraphQLAuth.call([]) assert conn.halted assert conn.status == 401 end end describe "call/2 with mobile session token" do setup do user = user_fixture() {:ok, session} = MobileSessions.create_mobile_session(%{ user_id: user.id, device_name: "Test iPhone" }) %{user: user, session: session} end test "authenticates and sets user but not org_id", %{ conn: conn, user: user, session: session } do conn = conn |> put_req_header("authorization", "Bearer #{session.raw_token}") |> GraphQLAuth.call([]) refute conn.halted assert conn.assigns.current_user.id == user.id refute Map.has_key?(conn.assigns, :current_organization_id) end test "returns 401 for expired mobile session", %{conn: conn} do user = user_fixture() expires_at = DateTime.add(DateTime.utc_now(), -1, :day) {:ok, session} = MobileSessions.create_mobile_session(%{ user_id: user.id, device_name: "Expired iPhone", expires_at: expires_at }) conn = conn |> put_req_header("authorization", "Bearer #{session.raw_token}") |> GraphQLAuth.call([]) assert conn.halted assert conn.status == 401 end end describe "call/2 with missing or invalid auth" do test "returns 401 when Authorization header is missing", %{conn: conn} do conn = GraphQLAuth.call(conn, []) assert conn.halted assert conn.status == 401 assert json_response(conn, 401) == %{"error" => "Missing or invalid Authorization header"} end test "returns 401 when token is completely invalid", %{conn: conn} do conn = conn |> put_req_header("authorization", "Bearer totally_invalid_token_xyz") |> GraphQLAuth.call([]) assert conn.halted assert conn.status == 401 end end end