Setting up Forgejo with OIDC

Posted on August 17, 2026

Today, I’m setting up Forgejo to be able to have a more readable way to publish source code, mainly my Nix configurations, at the moment. This should be straightforward according to the NixOS Wiki.

Mailer setup

I likely won’t have much use for the mailer feature as long as Forgjo is not federated, but since I have a mailserver running, I’m going to configure it. The noreply setup may turn out to be reusable for future services.

First, create a new account in Kanidm:

kanidm login --name idm_admin
kanidm person create noreply 'Does not accept mail'
kanidm person posix set noreply
kanidm person posix set-password noreply
kanidm person update noreply --mail noreply@m.filts.net

To make this noreply address reject email, log in to the Stalwart WebUI using the noreply credentials and create and activate a Sieve script, according to provokateurin:

require ["envelope", "reject"];

if envelope :localpart :is "to" "noreply" {
    reject "550 This is a no-reply address";
    stop;
}

Seting up OIDC

There is thread on Kanidm Discussions on how to integrate Forgejo, which indicates that we have to use Forgejo’s Web Administration UI to set up OpenID Connect. Indeed, the lengthy example configuration file gives no indication to the contrary.

So we have to start Forgejo with registration enabled. The module so far is

{
  lib,
  pkgs,
  config,
  ...
}:
let
  cfg = config.services.forgejo;
  srv = cfg.settings.server;
in
{
  services.nginx = {
    virtualHosts.${cfg.settings.server.DOMAIN} = {
      forceSSL = true;
      useACMEHost = "filts.net";
      extraConfig = ''
        client_max_body_size 512M;
      '';
      locations."/".proxyPass = "http://localhost:${toString srv.HTTP_PORT}";
    };
  };

  services.forgejo = {
    enable = true;
    # Enable support for Git Large File Storage
    lfs.enable = true;
    settings = {
      server = {
        DOMAIN = "git.filts.net";
        # You need to specify this to remove the port from URLs in the web UI.
        ROOT_URL = "https://${srv.DOMAIN}/";
        HTTP_PORT = 3000;
      };
      # You can temporarily allow registration to create an admin user.
      service.DISABLE_REGISTRATION = false;
      mailer = {
        ENABLED = true;
        SMTP_ADDR = "madalena.filts.net";
        FROM = "noreply@m.filts.net";
        USER = "noreply@m.filts.net";
      };
    };
    secrets = {
      mailer.PASSWD = config.sops.secrets.noreply-mail-password.path;
    };
  };

  sops.secrets.noreply-mail-password = {
    mode = "400";
    owner = "forgejo";
    group = "forgejo";
  };
}

I registered my user m, which as the first user, got administration rights, and configured OIDC following the linked thread. One small change I made, was not creating a forgejo_users group, to keep it simple, and instead used the built-in idm_all_persons group instead.

kanidm group create forgejo_admins
kanidm system oauth2 create forgejo "Forgejo Instance" https://git.filts.net
kanidm system oauth2 add-redirect-url forgejo https://git.filts.net/user/oauth2/kanidm/callback
kanidm system oauth2 prefer-short-username forgejo
kanidm system oauth2 update-scope-map forgejo idm_all_persons openid email profile ssh_publickeys
kanidm system oauth2 update-claim-map forgejo forgejo_role forgejo_admins admin
kanidm system oauth2 show-basic-secret forgejo
kanidm group add-members forgejo_admins m

In the Forgejo Admin UI under Identity & access > Authentication sources, I again followed the linked thread.

Authentication name

kanidm

OAuth2 provider

OpenID Connect

Client ID (Key)

forgejo

Client Secret

<Secret from kanidm system oauth2 show-basic-secret forgejo>

OpenID Connect Auto Discovery URL

https://id.filts.net/oauth2/openid/forgejo/.well-known/openid-configuration

Skip local 2FA

check

Additional scopes

email ssh_publickeys

I’m not yet sure, how ssh keys are supposed to work here, but the experience of adding ssh keys to Forgejo is nicer than to Kanidm anyway. I may investigate that later.

With that done, and the module settings changed to

      service = {
        DISABLE_REGISTRATION = false;
        ENABLE_INTERNAL_SIGNIN = false;
        ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
        SHOW_REGISTRATION_BUTTON = false;
      };

it was time to rebuild a final time.

The result

I rebuilt the system and after authenticating with Kanidm, I was asked to login to Forgejo using the credentials I used for setting up Forgejo, to link to the old account. This part, I was a bit nervous about. It was not clear, if I had to create an admin user with a name that won’t collide with my Kanidm account, but as it turned out, that would not have been necessary, thanks to the linking.

You can now view my Forgejo config including the whole context at git.filts.net/m/madalena/src/branch/master/forgejo.nix. So far, I am pretty happy with it. Browsing is snappy, which was the most important goal for me.