Deployment and lifecycle management for Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add dev-only login bypass with pre-shared token

Adds a /dev/login route (compile-time gated to dev/test) that
authenticates a dev user when given the correct SOWER_DEV_LOGIN_TOKEN.
This enables agent-browser and other dev tooling to get authenticated
sessions without an OIDC provider.

The token is generated into .dev-login-token via .envrc and exported
as SOWER_DEV_LOGIN_TOKEN.

sow-108

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+46
+3
.envrc
··· 23 23 export RELEASE_COOKIE 24 24 25 25 genSecret "$PWD/.dev-secret-key-base" 26 + genSecret "$PWD/.dev-login-token" 27 + SOWER_DEV_LOGIN_TOKEN=$(cat "$PWD/.dev-login-token") 28 + export SOWER_DEV_LOGIN_TOKEN 26 29 genSecret "$PWD/.dev-cloak-ecto" $PWD/bin/gen-cloak-key.exs 27 30 28 31 # shellcheck disable=SC2089
+36
apps/sower/lib/sower_web/controllers/dev_login_controller.ex
··· 1 + if Mix.env() in [:dev, :test] do 2 + defmodule SowerWeb.DevLoginController do 3 + use SowerWeb, :controller 4 + 5 + require Logger 6 + 7 + def login(conn, %{"token" => token}) do 8 + expected = System.get_env("SOWER_DEV_LOGIN_TOKEN") 9 + 10 + if expected != nil and Plug.Crypto.secure_compare(token, expected) do 11 + {:ok, user} = 12 + Sower.Accounts.find_or_create_user( 13 + "dev-user-oidc-id", 14 + %Ueberauth.Auth.Info{ 15 + name: "Dev User", 16 + email: "dev@localhost" 17 + } 18 + ) 19 + 20 + SowerWeb.UserAuth.log_in_user(conn, user) 21 + else 22 + Logger.warning(msg: "Dev login rejected", reason: "invalid or missing token") 23 + 24 + conn 25 + |> put_status(:unauthorized) 26 + |> text("unauthorized") 27 + end 28 + end 29 + 30 + def login(conn, _params) do 31 + conn 32 + |> put_status(:bad_request) 33 + |> text("missing token parameter") 34 + end 35 + end 36 + end
+7
apps/sower/lib/sower_web/router.ex
··· 114 114 post "/seeds", SeedController, :create 115 115 end 116 116 117 + if Mix.env() in [:dev, :test] do 118 + scope "/dev", SowerWeb do 119 + pipe_through :browser 120 + get "/login", DevLoginController, :login 121 + end 122 + end 123 + 117 124 scope "/auth" do 118 125 pipe_through :browser 119 126 get "/:provider", SowerWeb.AuthController, :request