Skip to content

jitsi-meet-keycloak-oidc-overlay

Overlays

A Nixpkgs overlay that bolts a Keycloak / OIDC SSO adapter into jitsi-meet's static output — and works around a qemu-user webpack crash so the overlay still evaluates on non-x86_64 builders (e.g. aarch64).

The problem

You want Jitsi Meet to authenticate through Keycloak (OIDC / SSO) instead of its built-in auth. Adapters exist that do this by dropping a few extra static HTML/TS files next to jitsi-meet's own assets plus a small side-car service. The Nix-friendly way to install those extra files is overrideAttrs on the jitsi-meet derivation, appending them in a late install phase.

Two traps make this trickier than it looks.

Trap 1 — you can just append; don't rebuild

jitsi-meet's output is platform-independent static web assets. The OIDC adapter is likewise just more static files. So there is no need to rebuild the (expensive, fragile) webpack bundle — copying the extra files into $out in an appended installPhase is enough.

Trap 2 — the webpack build dies under qemu-user emulation

If you build jitsi-meet for a foreign architecture through qemu-user emulation (a common setup: an aarch64 builder producing an x86_64 closure, or vice-versa), the webpack build crashes. V8's JIT emits an instruction the user-mode emulator can't translate and the process dies with:

uncaught target signal 4 (Illegal instruction)

Because the output is arch-independent, the fix is to not emulate the build at all. When the host platform isn't the native one, the overlay re-imports nixpkgs (pinned via prev.path) for the native system and reuses that natively-built jitsi-meet, then bolts the adapter onto it. The static files it produces are valid on the current host regardless.

Usage

This is a curried overlay — call import with your arguments first, then pass the result to nixpkgs.overlays:

nixpkgs.overlays = [
  (import ./jitsi-meet-keycloak-oidc-overlay {
    # Required: path to your OIDC adapter source tree (see layout below).
    adapterSrc = ./my-jitsi-oidc-adapter;

    # Optional: the arch you can build jitsi-meet natively for.
    # Defaults to "x86_64-linux".
    nativeSystem = "x86_64-linux";
  })
];

adapterSrc layout

The overlay merges your tree into the jitsi-meet output like this:

Source Destination
${adapterSrc}/*.ts $out/oidc-adapter/
${adapterSrc}/jitsi-meet/* $out/ (merged)

Point adapterSrc at a checkout of an upstream jitsi ⇄ Keycloak OIDC adapter (several open-source ones exist) or your own fork. It is deliberately a parameter rather than a vendored copy, so you supply — and license — the third-party adapter code yourself.

The side-car service

Most such adapters run a small server (often a Deno or Node process) that mints the JWT Jitsi expects from the Keycloak session. That service is out of scope for this overlay (the overlay only installs the static assets), but two things are worth flagging because they bite people:

  • Certificates. Adapters frequently ship a test launch command with a "trust any certificate" flag (e.g. --unsafely-ignore-certificate-errors) so they work against a Keycloak with a self-signed cert. Flip this off for production once Keycloak presents a trusted certificate.
  • Configuration is environment-driven. Adapter config (Keycloak origin, realm, client id, JWT app id/secret, listen host/port) is typically read from environment variables with placeholder defaults. Set every value explicitly; never ship the upstream example defaults.

Caveats

  • nativeSystem must be an architecture your builder can produce natively (native builder or a binary cache serving it). If it can't, you've only moved the emulation problem, not solved it.
  • The overlay pins the native nixpkgs to prev.path, i.e. the same nixpkgs the overlay is applied to — so both arches stay on one revision.
  • This installs assets only. Wiring up the OIDC side-car service, Keycloak client, and Jitsi config is left to your NixOS configuration.

Source

overlays/jitsi-meet-keycloak-oidc-overlay/default.nix
# jitsi-meet-keycloak-oidc-overlay
#
# A Nixpkgs overlay that bolts a Keycloak / OIDC SSO adapter into jitsi-meet's
# static web output via `overrideAttrs`, and dodges a qemu-user webpack crash
# on non-native builders by reusing the natively-built derivation.
#
# It is a *curried* overlay: import it with your arguments first, then hand the
# result to `nixpkgs.overlays`.
#
#   nixpkgs.overlays = [
#     (import ./jitsi-meet-keycloak-oidc-overlay {
#       adapterSrc = ./my-jitsi-oidc-adapter;   # your OIDC adapter tree
#       # nativeSystem = "x86_64-linux";        # default; the arch you can build natively
#     })
#   ];
#
# See README.md for what `adapterSrc` must contain and the traps involved.

{
  # Path to your OIDC adapter source tree. Its layout is merged into the
  # jitsi-meet output like so:
  #   ${adapterSrc}/*.ts          -> copied into $out/oidc-adapter/
  #   ${adapterSrc}/jitsi-meet/*  -> merged into $out/ (static HTML shims etc.)
  #
  # This is intentionally *your* tree, not a vendored copy: point it at a
  # checkout of an upstream jitsi <-> Keycloak OIDC adapter (several exist),
  # or at your own fork. Keeping it a parameter avoids re-vendoring a
  # third-party, separately-licensed codebase inside this overlay.
  adapterSrc,

  # The system whose *natively built* jitsi-meet is reused when the host
  # platform cannot run the webpack build under emulation. This must be a
  # platform your builder can produce natively (native builder or a binary
  # cache), otherwise you just move the emulation problem, you don't solve it.
  nativeSystem ? "x86_64-linux",
}:

# Standard overlay signature. `prev` is the un-overlaid package set; we don't
# need `final` here.
final: prev:
let
  # Bolt the adapter's static assets into a jitsi-meet derivation's output.
  # jitsi-meet ships plain static web assets, so appending files in a late
  # install phase is enough — no rebuild of the webpack bundle is required.
  addOidc =
    jm:
    jm.overrideAttrs (old: {
      installPhase = (old.installPhase or "") + ''
        mkdir -p $out/oidc-adapter
        cp -r ${adapterSrc}/*.ts $out/oidc-adapter/
        cp -r ${adapterSrc}/jitsi-meet/* $out/
      '';
    });
in
{
  jitsi-meet =
    if prev.stdenv.hostPlatform.system == nativeSystem then
      # Native host: just override the package set's own jitsi-meet.
      addOidc prev.jitsi-meet
    else
      # Non-native host (e.g. aarch64 building for x86_64-native tooling):
      #
      # jitsi-meet's *output* is platform-independent static web assets, but its
      # webpack build crashes under qemu-user emulation — the V8 JIT emits an
      # instruction qemu-user can't translate and the process dies with
      # "uncaught target signal 4 (Illegal instruction)".
      #
      # Since the output is arch-independent, we sidestep emulation entirely:
      # re-import nixpkgs (pinned via `prev.path`) *for the native system* and
      # reuse that natively-built jitsi-meet, then bolt the adapter onto it.
      # The result is still a valid derivation for the current host because the
      # files it contains are just static assets.
      addOidc
        (import prev.path {
          system = nativeSystem;
          config = prev.config;
        }).jitsi-meet;
}