1
0
Fork 0
mirror of https://github.com/nix-community/home-manager.git synced 2025-11-08 19:46:05 +01:00

pizauth: init module

This commit is contained in:
Leon Schwarzäugl 2025-08-09 16:23:53 +02:00 committed by Austin Horstman
parent 0b7147a547
commit 18ea6d7a8f
4 changed files with 274 additions and 0 deletions

View file

@ -0,0 +1,12 @@
{ pkgs, ... }:
{
time = "2025-08-09T22:11:00+00:00";
condition = pkgs.stdenv.hostPlatform.isLinux;
message = ''
A new service is available: 'services.pizauth'.
Pizauth is a simple program for requesting, showing, and refreshing OAuth2 access tokens.
Pizauth is formed of two components: a persistent server which interacts with the user to request tokens, and refreshes them as necessary;
and a command-line interface which can be used by programs such as fdm and msmtp to authenticate with OAuth2.
'';
}

View file

@ -0,0 +1,190 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) mkOption types;
cfg = config.services.pizauth;
in
{
meta.maintainers = [ lib.hm.maintainers.swarsel ];
options.services.pizauth = {
enable = lib.mkEnableOption ''
Pizauth, a commandline OAuth2 authentication daemon
'';
package = lib.mkPackageOption pkgs "pizauth" { };
extraConfig = mkOption {
type = types.nullOr types.str;
default = null;
description = "Additional global configuration. See pizauth.conf(5) for a available options.";
};
accounts = mkOption {
type = types.attrsOf (
types.submodule {
options = {
name = mkOption {
type = types.str;
readOnly = true;
description = ''
Unique identifier of the account. This is set to the
attribute name of the account configuration.
'';
};
authUri = mkOption {
type = types.str;
description = ''
The OAuth2 server's authentication URI.
'';
};
tokenUri = mkOption {
type = types.str;
description = ''
The OAuth2 server's token URI.
'';
};
clientId = mkOption {
type = types.str;
description = ''
The OAuth2 client ID.
'';
};
clientSecret = mkOption {
type = types.str;
description = ''
The OAuth2 client secret.
'';
};
scopes = mkOption {
type = types.nullOr (types.listOf types.str);
description = ''
The scopes which the OAuth2 token will give access to. Optional.
Note that Office365 requires the non-standard "offline_access" scope to be specified in order for pizauth to be able to operate successfully.
'';
default = [ ];
example = [
"https://outlook.office365.com/IMAP.AccessAsUser.All"
"https://outlook.office365.com/SMTP.Send"
"offline_access"
];
};
loginHint = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
An optional login hint for the account provider.
'';
};
extraConfig = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Additional configuration that will be added to the account configuration. See pizauth.conf(5) for available options.
'';
};
};
}
);
default = { };
description = "Pizauth accounts that should be configured";
};
};
config = lib.mkIf cfg.enable {
assertions = [ (lib.hm.assertions.assertPlatform "services.pizauth" pkgs lib.platforms.linux) ];
home.packages = [ cfg.package ];
xdg.configFile."pizauth.conf".source =
let
indent = " ";
renderScopes =
scopes:
let
quoted = map (s: "\"${s}\"") scopes;
joined = lib.concatStringsSep ",\n${indent}${indent}" quoted;
in
"[\n${indent}${indent}${joined}\n${indent}]";
renderAccount =
name: acc:
''
account "${name}" {
${indent}auth_uri = "${acc.authUri}";
${indent}token_uri = "${acc.tokenUri}";
${indent}client_id = "${acc.clientId}";
${indent}client_secret = "${acc.clientSecret}";
''
+ lib.optionalString (acc.scopes != [ ] && acc.scopes != null) ''
${indent}scopes = ${renderScopes acc.scopes};
''
+ lib.optionalString (acc.loginHint != "" && acc.loginHint != null) ''
${indent}login_hint = "${acc.loginHint}";
''
+ lib.optionalString (acc.extraConfig != "" && acc.extraConfig != null) (
let
indentedExtraConfig = lib.concatMapStringsSep "\n" (
line: if line == "" then "" else "${indent}${line}"
) (lib.splitString "\n" acc.extraConfig);
in
indentedExtraConfig
)
+ ''
}
'';
renderedAccounts = lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: acc: renderAccount name acc) cfg.accounts
);
in
pkgs.writeTextFile {
name = "pizauth.conf";
text =
lib.optionalString (cfg.extraConfig != null && cfg.extraConfig != "") "${cfg.extraConfig}\n"
+ renderedAccounts;
};
systemd.user.services.pizauth = {
Unit = {
Description = "Pizauth OAuth2 token manager";
After = [ "network.target" ];
};
Service = {
Type = "simple";
ExecStart = "${lib.getExe cfg.package} server -vvvv -d";
ExecReload = "${lib.getExe cfg.package} reload";
ExecStop = "${lib.getExe cfg.package} shutdown";
Restart = "on-failure";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateUsers = true;
RestrictNamespaces = true;
SystemCallArchitectures = "native";
SystemCallFilter = "@system-service";
};
Install = {
WantedBy = [ "default.target" ];
};
};
};
}

View file

@ -0,0 +1,70 @@
{ pkgs, ... }:
{
config = {
services.pizauth = {
enable = true;
extraConfig = ''
refresh_at_least = 15s;
'';
accounts = {
test1 = {
authUri = "authUri1";
tokenUri = "tokenUri1";
clientId = "clientId1";
clientSecret = "clientSecret1";
loginHint = "testLogin1";
extraConfig = ''
redirectUri = "redirectUri1";
refresh_retry = 30s;
'';
};
test2 = {
authUri = "authUri2";
tokenUri = "tokenUri2";
clientId = "clientId2";
clientSecret = "clientSecret2";
scopes = [
"scope1"
"offline_access"
];
};
};
};
test.stubs.pizauth = { };
nmt.script = ''
local serviceFile=home-files/.config/systemd/user/pizauth.service
assertFileExists $serviceFile
assertFileRegex $serviceFile 'ExecStart=.*/bin/dummy server -vvvv -d'
assertFileExists home-files/.config/pizauth.conf
assertFileContent home-files/.config/pizauth.conf \
${pkgs.writeText "expected-config" ''
refresh_at_least = 15s;
account "test1" {
auth_uri = "authUri1";
token_uri = "tokenUri1";
client_id = "clientId1";
client_secret = "clientSecret1";
login_hint = "testLogin1";
redirectUri = "redirectUri1";
refresh_retry = 30s;
}
account "test2" {
auth_uri = "authUri2";
token_uri = "tokenUri2";
client_id = "clientId2";
client_secret = "clientSecret2";
scopes = [
"scope1",
"offline_access"
];
}
''}
'';
};
}

View file

@ -0,0 +1,2 @@
{ lib, pkgs, ... }:
lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { pizauth-basic-config = ./basic-config.nix; }