diff --git a/lib/cms_web/components/layouts/app.html.heex b/lib/cms_web/components/layouts/app.html.heex
index 3c0707f..fbe0799 100644
--- a/lib/cms_web/components/layouts/app.html.heex
+++ b/lib/cms_web/components/layouts/app.html.heex
@@ -11,7 +11,9 @@
   </section>
 
   <section class="flex flex-row">
-    <.link href={~p"/admin/session"} method="delete" class="hover:underline">sign out</.link>
+    <.link href={~p"/admin/session/destroy?return_to=#{@current_path}"} class="hover:underline">
+      sign out
+    </.link>
   </section>
 </div>
 <div class="flex flex-col md:flex-row mx-auto max-w-4xl">
@@ -28,3 +30,9 @@
     {@inner_content}
   </main>
 </div>
+<div
+  :if={not @admin?}
+  class="fixed right-0 bottom-0 p-2 text-transparent underline hover:text-current"
+>
+  <.link href={~p"/sign-in?return_to=#{@current_path}"}>sign in</.link>
+</div>
diff --git a/lib/cms_web/controllers/admin_auth.ex b/lib/cms_web/controllers/admin_auth.ex
index 3f8e346..e671dc6 100644
--- a/lib/cms_web/controllers/admin_auth.ex
+++ b/lib/cms_web/controllers/admin_auth.ex
@@ -5,21 +5,33 @@ defmodule CMSWeb.AdminAuth do
   import Phoenix.Controller
   import Plug.Conn
 
-  def log_in_admin(conn) do
+  def log_in_admin(conn, params) do
     conn
     |> renew_session()
     |> put_session(:admin?, true)
-    |> redirect(to: ~p"/")
+    |> redirect(to: params["return_to"] || ~p"/admin")
   end
 
-  def log_out_admin(conn) do
+  def log_out_admin(conn, params) do
     if live_socket_id = get_session(conn, :live_socket_id) do
       CMSWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
     end
 
     conn
     |> renew_session()
-    |> redirect(to: ~p"/")
+    |> redirect(to: params["return_to"] || ~p"/")
+  end
+
+  def mount_admin(%Plug.Conn{} = conn, _opts) do
+    assign(conn, :admin?, admin?(conn))
+  end
+
+  def require_admin(%Plug.Conn{assigns: %{admin?: true}} = conn, _opts) do
+    conn
+  end
+
+  def require_admin(conn, _opts) do
+    redirect(conn, to: ~p"/sign-in?return_to=#{conn.request_path}")
   end
 
   def correct_password?(password) do
@@ -28,6 +40,10 @@ defmodule CMSWeb.AdminAuth do
     Argon2.verify_pass(password, password_hash)
   end
 
+  def on_mount(:default, _params, session, socket) do
+    {:cont, Phoenix.Component.assign(socket, :admin?, admin?(session))}
+  end
+
   ## private
 
   defp renew_session(conn) do
@@ -37,4 +53,10 @@ defmodule CMSWeb.AdminAuth do
     |> configure_session(renew: true)
     |> clear_session()
   end
+
+  defp admin?(%Plug.Conn{} = conn) do
+    Plug.Conn.get_session(conn, :admin?, false) == true
+  end
+
+  defp admin?(%{} = session), do: Map.get(session, "admin?", false) == true
 end
diff --git a/lib/cms_web/controllers/admin_mode.ex b/lib/cms_web/controllers/admin_mode.ex
deleted file mode 100644
index 2c67d43..0000000
--- a/lib/cms_web/controllers/admin_mode.ex
+++ /dev/null
@@ -1,18 +0,0 @@
-defmodule CMSWeb.AdminMode do
-  @moduledoc false
-  use CMSWeb, :live_view
-
-  def admin_mode(%Plug.Conn{} = conn, _opts) do
-    Plug.Conn.assign(conn, :admin?, admin?(conn))
-  end
-
-  def on_mount(:default, _params, session, socket) do
-    {:cont, assign(socket, :admin?, admin?(session))}
-  end
-
-  defp admin?(%Plug.Conn{} = conn) do
-    Plug.Conn.get_session(conn, :admin?, false) == true
-  end
-
-  defp admin?(%{} = session), do: Map.get(session, :admin?, false) == true
-end
diff --git a/lib/cms_web/controllers/admin_session_controller.ex b/lib/cms_web/controllers/admin_session_controller.ex
index 139d944..a205f39 100644
--- a/lib/cms_web/controllers/admin_session_controller.ex
+++ b/lib/cms_web/controllers/admin_session_controller.ex
@@ -3,21 +3,19 @@ defmodule CMSWeb.AdminSessionController do
 
   alias CMSWeb.AdminAuth
 
-  def create(conn, %{"password" => password}) do
+  def create(conn, %{"password" => password} = params) do
     if AdminAuth.correct_password?(password) do
-      AdminAuth.log_in_admin(conn)
+      AdminAuth.log_in_admin(conn, params)
     else
-      redirect(conn, to: ~p"/admin/sign-in")
+      redirect(conn, to: ~p"/sign-in")
     end
   end
 
   def create(conn, _params) do
-    redirect(conn, to: ~p"/admin/sign-in")
+    redirect(conn, to: ~p"/sign-in")
   end
 
-  def destroy(conn, _params) do
-    conn
-    |> AdminAuth.log_out_admin()
-    |> redirect(to: ~p"/")
+  def destroy(conn, params) do
+    AdminAuth.log_out_admin(conn, params)
   end
 end
diff --git a/lib/cms_web/controllers/globals.ex b/lib/cms_web/controllers/globals.ex
new file mode 100644
index 0000000..5001685
--- /dev/null
+++ b/lib/cms_web/controllers/globals.ex
@@ -0,0 +1,18 @@
+defmodule CMSWeb.Globals do
+  @moduledoc false
+  use CMSWeb, :live_view
+
+  def assign_globals(%Plug.Conn{} = conn, _opts) do
+    Plug.Conn.assign(conn, :current_path, conn.request_path)
+  end
+
+  def on_mount(:default, _params, _session, socket) do
+    socket =
+      attach_hook(socket, :assign_handle_params_globals, :handle_params, fn _params, uri, socket ->
+        %URI{path: current_path} = URI.parse(uri)
+        {:cont, assign(socket, :current_path, current_path)}
+      end)
+
+    {:cont, socket}
+  end
+end
diff --git a/lib/cms_web/live/admin_login_live.ex b/lib/cms_web/live/admin_login_live.ex
index 2d97891..ef229cd 100644
--- a/lib/cms_web/live/admin_login_live.ex
+++ b/lib/cms_web/live/admin_login_live.ex
@@ -3,27 +3,37 @@ defmodule CMSWeb.AdminLoginLive do
   use CMSWeb, :live_view
 
   @impl true
-  def mount(_params, _session, socket) do
-    socket = assign(socket, :form, to_form(%{"password" => ""}))
+  def mount(params, _session, socket) do
+    socket = assign(socket, :form, to_form(%{"password" => "", "return_to" => params["return_to"]}))
 
-    {:ok, socket}
+    {:ok, socket, layout: false}
   end
 
   @impl true
   def render(assigns) do
     ~H"""
-    <h1 class="font-bold text-lg mb-4">Sign in</h1>
-
-    <.form for={@form} action={~p"/admin/session"}>
-      <input
-        type="password"
-        placeholder="password"
-        id={@form[:password].id}
-        name={@form[:password].name}
-        value={@form[:password].value}
-        required
-      />
-    </.form>
+    <main class="flex flex-col w-screen h-screen fixed justify-center items-center">
+      <.form for={@form} action={~p"/admin/session/create"} class="flex flex-col gap-y-2">
+        <input
+          type="hidden"
+          id={@form[:return_to].id}
+          name={@form[:return_to].name}
+          value={@form[:return_to].value}
+        />
+        <input
+          type="password"
+          placeholder="password"
+          id={@form[:password].id}
+          name={@form[:password].name}
+          value={@form[:password].value}
+          required
+        />
+        <div class="flex flex-col items-end">
+          <button type="submit" class="font-bold hover:underline">sign in</button>
+          <.link href={~p"/"} class="hover:underline">cancel</.link>
+        </div>
+      </.form>
+    </main>
     """
   end
 end
diff --git a/lib/cms_web/router.ex b/lib/cms_web/router.ex
index e5c97de..6a5885b 100644
--- a/lib/cms_web/router.ex
+++ b/lib/cms_web/router.ex
@@ -1,9 +1,11 @@
 defmodule CMSWeb.Router do
   use CMSWeb, :router
 
-  import CMSWeb.AdminMode
+  import CMSWeb.AdminAuth
+  import CMSWeb.Globals
 
-  alias CMSWeb.AdminMode
+  alias CMSWeb.AdminAuth
+  alias CMSWeb.Globals
 
   pipeline :browser do
     plug :accepts, ["html"]
@@ -12,23 +14,37 @@ defmodule CMSWeb.Router do
     plug :put_root_layout, html: {CMSWeb.Layouts, :root}
     plug :protect_from_forgery
     plug :put_secure_browser_headers
-    plug :admin_mode
+    plug :assign_globals
   end
 
-  live_session :default, on_mount: AdminMode do
+  pipeline :supports_admin_action do
+    plug :mount_admin
+  end
+
+  pipeline :requires_admin do
+    plug :mount_admin
+    plug :require_admin
+  end
+
+  live_session :default, on_mount: [AdminAuth, Globals] do
     scope "/", CMSWeb do
       pipe_through :browser
+      pipe_through :supports_admin_action
 
       get "/", PageController, :home
       get "/writing", PageController, :writing
       get "/microblog", PageController, :microblog
 
-      live "/admin", AdminLive
+      live "/sign-in", AdminLoginLive
+      post "/admin/session/create", AdminSessionController, :create
+      get "/admin/session/destroy", AdminSessionController, :destroy
+    end
 
-      live "/admin/sign-in", AdminLoginLive
+    scope "/admin", CMSWeb do
+      pipe_through :browser
+      pipe_through :requires_admin
 
-      post "/admin/session", AdminSessionController, :create
-      delete "/admin/session", AdminSessionController, :destroy
+      live "/", AdminLive
     end
   end