defmodule Localiser.Web.Controllers.SessionController do use Phoenix.Controller, formats: [:json] use OpenApiSpex.ControllerSpecs alias Localiser.Domain.Users alias Localiser.Web.Token alias Localiser.Web.Schemas tags ["Auth"] security [] operation :create, summary: "Log in and receive a JWT", request_body: {"Login params", "application/json", Schemas.SessionParams, required: true}, responses: [ ok: {"JWT + user", "application/json", Schemas.TokenResponse}, bad_request: {"Missing username/password", "application/json", Schemas.Error}, unauthorized: {"Invalid credentials", "application/json", Schemas.Error} ] operation :delete, summary: "Log out (client discards token)", responses: [no_content: "Logged out"] def create(conn, %{"username" => username, "password" => password}) do case Users.authenticate_user(username, password) do {:ok, user} -> token = Token.generate(%{"sub" => user.id, "username" => user.username, "is_admin" => user.is_admin}) json(conn, %{token: token, user: render_user(user)}) {:error, :invalid_credentials} -> conn |> put_status(:unauthorized) |> json(%{error: "invalid credentials"}) end end def create(conn, _params) do conn |> put_status(:bad_request) |> json(%{error: "username and password are required"}) end def delete(conn, _params) do # JWT is stateless; client discards token send_resp(conn, :no_content, "") end defp render_user(user) do %{id: user.id, username: user.username, is_admin: user.is_admin} end end