anchor.diff:          description = lib.mdDoc "Group account under which PrivacyIDEA runs.";
         };
   
  +      tokenjanitor = {
  +        enable = mkEnableOption "automatic runs of the token janitor";
  +        interval = mkOption {
  +          default = "quarterly";
  +          type = types.str;
  +          description = lib.mdDoc ''
  +            Interval in which the cleanup program is supposed to run.
  +            See {manpage}`systemd.time(7)` for further information.
  +          '';
  +        };
  +        action = mkOption {
  +          type = types.enum [ "delete" "mark" "disable" "unassign" ];
  +          description = lib.mdDoc ''
  +            Which action to take for matching tokens.
  +          '';
  +        };
  +        unassigned = mkOption {
  +          default = false;
  +          type = types.bool;
  +          description = lib.mdDoc ''
  +            Whether to search for **unassigned** tokens
  +            and apply [](#opt-services.privacyidea.tokenjanitor.action)
  +            onto them.
  +          '';
  +        };
  +        orphaned = mkOption {
  +          default = true;
  +          type = types.bool;
  +          description = lib.mdDoc ''
  +            Whether to search for **orphaned** tokens
  +            and apply [](#opt-services.privacyidea.tokenjanitor.action)
  +            onto them.
  +          '';
  +        };
  +      };
  +
         ldap-proxy = {
           enable = mkEnableOption (lib.mdDoc "PrivacyIDEA LDAP Proxy");
   
  
positive.code:       (flip mapAttrs cfg.ldap-proxy.settings
          (const (mapAttrs (const renderValue)))));
  
  in
  
  {
  
negative.code: 
      (mkIf cfg.enable {
  
        assertions = [
          {
            assertion = cfg.tokenjanitor.enable -> (cfg.tokenjanitor.orphaned || cfg.tokenjanitor.unassigned);
            message = ''
              privacyidea-token-janitor has no effect if neither orphaned nor unassigned tokens
              are to be searched.
            '';
          }
        ];
  
        environment.systemPackages = [ pkgs.privacyidea (hiPrio privacyidea-token-janitor) ];
  
        services.postgresql.enable = mkDefault true;
  
        systemd.services.privacyidea-tokenjanitor = mkIf cfg.tokenjanitor.enable {
          environment.PRIVACYIDEA_CONFIGFILE = "${cfg.stateDir}/privacyidea.cfg";
          path = [ penv ];
          serviceConfig = {
            CapabilityBoundingSet = [ "" ];
            ExecStart = "${pkgs.writeShellScript "pi-token-janitor" ''
              ${optionalString cfg.tokenjanitor.orphaned ''
                echo >&2 "Removing orphaned tokens..."
                privacyidea-token-janitor find \
                  --orphaned true \
                  --action ${cfg.tokenjanitor.action}
              ''}
              ${optionalString cfg.tokenjanitor.unassigned ''
                echo >&2 "Removing unassigned tokens..."
                privacyidea-token-janitor find \
                  --assigned false \
                  --action ${cfg.tokenjanitor.action}
              ''}
            ''}";
            Group = cfg.group;
            LockPersonality = true;
            MemoryDenyWriteExecute = true;
            ProtectHome = true;
            ProtectHostname = true;
            ProtectKernelLogs = true;
            ProtectKernelModules = true;
            ProtectKernelTunables = true;
            ProtectSystem = "strict";
            ReadWritePaths = cfg.stateDir;
            Type = "oneshot";
            User = cfg.user;
            WorkingDirectory = cfg.stateDir;
          };
        };
        systemd.timers.privacyidea-tokenjanitor = mkIf cfg.tokenjanitor.enable {
          wantedBy = [ "timers.target" ];
          timerConfig.OnCalendar = cfg.tokenjanitor.interval;
          timerConfig.Persistent = true;
        };
  
        systemd.services.privacyidea = let
          piuwsgi = pkgs.writeText "uwsgi.json" (builtins.toJSON {
  