From 82f035f07779e1f80f1b45954d451b9d5267115e Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Sat, 7 Mar 2026 14:11:01 -0500 Subject: [PATCH] tinyauth: init at 5.0.1 --- .../manual/release-notes/rl-2605.section.md | 2 + nixos/modules/module-list.nix | 1 + nixos/modules/services/security/tinyauth.nix | 246 ++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/tinyauth.nix | 31 +++ pkgs/by-name/ti/tinyauth/package.nix | 112 ++++++++ 6 files changed, 393 insertions(+) create mode 100644 nixos/modules/services/security/tinyauth.nix create mode 100644 nixos/tests/tinyauth.nix create mode 100644 pkgs/by-name/ti/tinyauth/package.nix diff --git a/nixos/doc/manual/release-notes/rl-2605.section.md b/nixos/doc/manual/release-notes/rl-2605.section.md index 9363f4580653..425eb918392e 100644 --- a/nixos/doc/manual/release-notes/rl-2605.section.md +++ b/nixos/doc/manual/release-notes/rl-2605.section.md @@ -58,6 +58,8 @@ - [Ente Auth](https://ente.io/auth/), an open source 2FA authenticator, with end-to-end encrypted backups. Available as [programs.ente-auth](#opt-programs.ente-auth.enable). +- [Tinyauth](https://tinyauth.app/), a simple authentication middleware for web apps, with OAuth and LDAP support. Available as [services.tinyauth](#opt-services.tinyauth.enable). + - [Dawarich](https://dawarich.app/), a self-hostable location history tracker. Available as [services.dawarich](#opt-services.dawarich.enable). - [Howdy](https://github.com/boltgolt/howdy), a Windows Helloâ„¢ style facial authentication program for Linux. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 75c6a35e5115..532ce6340f05 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1525,6 +1525,7 @@ ./services/security/step-ca.nix ./services/security/tang.nix ./services/security/timekpr.nix + ./services/security/tinyauth.nix ./services/security/tor.nix ./services/security/torify.nix ./services/security/torsocks.nix diff --git a/nixos/modules/services/security/tinyauth.nix b/nixos/modules/services/security/tinyauth.nix new file mode 100644 index 000000000000..3cceabecfb64 --- /dev/null +++ b/nixos/modules/services/security/tinyauth.nix @@ -0,0 +1,246 @@ +{ + lib, + pkgs, + config, + ... +}: + +let + inherit (lib) + getExe + maintainers + mapAttrs' + mkEnableOption + mkIf + mkOption + mkPackageOption + nameValuePair + optionalAttrs + types + ; + + cfg = config.services.tinyauth; + + format = pkgs.formats.keyValue { }; + settingsFile = format.generate "tinyauth-env-vars" ( + mapAttrs' (name: value: nameValuePair "TINYAUTH_${name}" value) cfg.settings + ); +in +{ + options.services.tinyauth = { + enable = mkEnableOption "Tinyauth server"; + + package = mkPackageOption pkgs "tinyauth" { }; + + environmentFile = mkOption { + type = types.path; + description = '' + Path to an environment file loaded for Tinyauth. + + This can be used to securely store tokens and secrets outside of the world-readable Nix store. + + Example contents of the file: + ``` + TINYAUTH_AUTH_USERS=user-hash + TINYAUTH_OAUTH_PROVIDERS_GOOGLE_CLIENTSECRET=client-secret + ``` + ''; + default = "/dev/null"; + example = "/var/lib/secrets/tinyauth"; + }; + + settings = mkOption { + type = types.submodule { + freeformType = format.type; + + options = { + SERVER_ADDRESS = mkOption { + type = types.str; + description = '' + Address to bind the server to. + ''; + default = "0.0.0.0"; + }; + + SERVER_PORT = mkOption { + type = types.port; + description = '' + The port to run the server on. + ''; + default = 3000; + }; + + APPURL = mkOption { + type = types.str; + description = '' + URL of the app. + ''; + example = "https://auth.example.com"; + }; + + ANALYTICS_ENABLED = mkOption { + type = types.bool; + description = '' + Whether to enable anonymous version collection. + ''; + default = false; + }; + + RESOURCES_ENABLED = mkOption { + type = types.bool; + description = '' + Whether to enable the resources server. + ''; + default = true; + }; + + AUTH_LOGINMAXRETRIES = mkOption { + type = types.ints.unsigned; + description = '' + Maximum login attempts before timeout (0 to disable). + ''; + default = 3; + }; + + AUTH_LOGINTIMEOUT = mkOption { + type = types.ints.unsigned; + description = '' + Login timeout in seconds after max retries reached (0 to disable). + ''; + default = 300; + }; + + AUTH_TRUSTEDPROXIES = mkOption { + type = types.str; + description = '' + Comma-separated list of trusted proxy addresses. + ''; + default = ""; + }; + }; + }; + + default = { }; + + description = '' + Environment variables that will be passed to Tinyauth. + The "TINYAUTH_" prefix will be prepended to the setting names. + See [configuration options](https://tinyauth.app/docs/reference/configuration) + for supported values. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/tinyauth"; + description = '' + The directory where Tinyauth will store its data. + ''; + }; + + user = mkOption { + type = types.str; + default = "tinyauth"; + description = "User account under which Tinyauth runs."; + }; + + group = mkOption { + type = types.str; + default = "tinyauth"; + description = "Group account under which Tinyauth runs."; + }; + }; + + config = mkIf cfg.enable { + systemd.tmpfiles.settings.tinyauth = { + "${cfg.dataDir}".d = { + mode = "0750"; + user = cfg.user; + group = cfg.group; + }; + }; + + systemd.services.tinyauth = { + description = "Tinyauth"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ + cfg.package + cfg.environmentFile + settingsFile + ]; + + environment = { + GIN_MODE = "release"; + TINYAUTH_DATABASE_PATH = "${cfg.dataDir}/tinyauth.db"; + TINYAUTH_RESOURCES_PATH = "${cfg.dataDir}/resources"; + }; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + WorkingDirectory = cfg.dataDir; + ExecStart = getExe cfg.package; + Restart = "always"; + + EnvironmentFile = [ + cfg.environmentFile + settingsFile + ]; + + # Hardening + AmbientCapabilities = ""; + CapabilityBoundingSet = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = "disconnected"; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ReadWritePaths = [ cfg.dataDir ]; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_UNIX" + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "~@resources" + ]; + UMask = "0077"; + }; + }; + + users.users = optionalAttrs (cfg.user == "tinyauth") { + tinyauth = { + isSystemUser = true; + group = cfg.group; + description = "Tinyauth user"; + home = cfg.dataDir; + }; + }; + + users.groups = optionalAttrs (cfg.group == "tinyauth") { + tinyauth = { }; + }; + }; + + meta.maintainers = with maintainers; [ shaunren ]; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index d9feaf85da01..d89792777cca 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1643,6 +1643,7 @@ in timezone = runTest ./timezone.nix; timidity = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./timidity { }; tinc = handleTest ./tinc { }; + tinyauth = runTest ./tinyauth.nix; tinydns = runTest ./tinydns.nix; tinyproxy = runTest ./tinyproxy.nix; tinywl = runTest ./tinywl.nix; diff --git a/nixos/tests/tinyauth.nix b/nixos/tests/tinyauth.nix new file mode 100644 index 000000000000..c5abb3592429 --- /dev/null +++ b/nixos/tests/tinyauth.nix @@ -0,0 +1,31 @@ +{ lib, pkgs, ... }: + +let + port = 3001; +in +{ + name = "tinyauth"; + meta.maintainers = with lib.maintainers; [ shaunren ]; + + nodes.machine = { + services.tinyauth = { + enable = true; + settings = { + APPURL = "http://auth.example.com"; + SERVER_PORT = port; + ANALYTICS_ENABLED = false; + }; + + environmentFile = pkgs.writeText "tinyauth-env" '' + TINYAUTH_AUTH_USERS=test:$$2a$$10$$NP5wKRFw5GuVVI.g07zvAucRYk0cyL83WDPVQ81Zai.Xi5tkNvxL6 + ''; + }; + }; + + testScript = '' + machine.wait_for_unit("tinyauth.service") + machine.wait_for_open_port(${toString port}) + + machine.succeed("curl -sSf -H Host:auth.example.com http://localhost:${toString port}") + ''; +} diff --git a/pkgs/by-name/ti/tinyauth/package.nix b/pkgs/by-name/ti/tinyauth/package.nix new file mode 100644 index 000000000000..1dc47be0a486 --- /dev/null +++ b/pkgs/by-name/ti/tinyauth/package.nix @@ -0,0 +1,112 @@ +{ + lib, + buildGoModule, + fetchFromGitHub, + git, + stdenvNoCC, + bun, + nixosTests, + nix-update-script, +}: + +buildGoModule (finalAttrs: { + pname = "tinyauth"; + version = "5.0.1"; + + src = fetchFromGitHub { + owner = "steveiliop56"; + repo = "tinyauth"; + tag = "v${finalAttrs.version}"; + fetchSubmodules = true; + hash = "sha256-ypM56yrUWF1OzCj5RBGyEhZzjyDcko7SPQ+eVhHEzmA="; + }; + + vendorHash = "sha256-qELLarAR78WkDoJKtqaqzIZaTBCuHP41JCyjLZ4aMtM="; + + subPackages = [ "cmd/tinyauth" ]; + + env.CGO_ENABLED = 0; + ldflags = [ + "-s" + "-w" + "-X tinyauth/internal/config.Version=v${finalAttrs.version}" + "-X tinyauth/internal/config.CommitHash=${finalAttrs.src.rev}" + ]; + + preBuild = '' + cp -r ${finalAttrs.frontend}/dist internal/assets/dist + ''; + + postPatch = '' + ${lib.getExe git} apply --directory paerser/ patches/nested_maps.diff + ''; + + frontend = stdenvNoCC.mkDerivation { + pname = "tinyauth-frontend"; + inherit (finalAttrs) version src; + sourceRoot = "${finalAttrs.src.name}/frontend"; + + impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ + "GIT_PROXY_COMMAND" + "SOCKS_SERVER" + ]; + + nativeBuildInputs = [ + bun + ]; + + configurePhase = '' + runHook preConfigure + + bun install --no-progress --frozen-lockfile + substituteInPlace node_modules/.bin/{tsc,vite} \ + --replace-fail "/usr/bin/env node" "${lib.getExe bun}" + + runHook postConfigure + ''; + + buildPhase = '' + runHook preBuild + + bun run build + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/dist + cp -r dist $out + + runHook postInstall + ''; + + outputHashMode = "recursive"; + outputHash = "sha256-pB94TUwjm5GmEmgjqkr7QH9BoRhKCSbxQVOc+2fCz2c="; + }; + + passthru = { + tests = { + inherit (nixosTests) tinyauth; + }; + updateScript = nix-update-script { + extraArgs = [ + "--subpackage" + "frontend" + ]; + }; + }; + + meta = { + description = "Simple authentication middleware for web apps"; + homepage = "https://tinyauth.app"; + changelog = "https://github.com/steveiliop56/tinyauth/releases/tag/v${finalAttrs.version}"; + license = lib.licenses.gpl3Only; + mainProgram = "tinyauth"; + maintainers = with lib.maintainers; [ + shaunren + ]; + platforms = lib.platforms.unix; + }; +})