From 17ddca8cdb19e8f1c98b8bb0439ede9094521dd6 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 3 Dec 2025 19:20:33 +0000 Subject: [PATCH 1/6] chore(deps): update renovate/renovate docker tag to v42 --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 483a08a..0615c71 100644 --- a/.drone.yml +++ b/.drone.yml @@ -166,7 +166,7 @@ environment: steps: - name: renovate - image: renovate/renovate:41.173 + image: renovate/renovate:42.33 environment: RENOVATE_CONFIG_FILE: "renovate_backend_config.js" RENOVATE_TOKEN: From f0391d3fefeba5353edccea81cbcfdcd4914ef9c Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 3 Dec 2025 20:34:33 +0100 Subject: [PATCH 2/6] fix: oidc with authentik not working --- README.md | 31 +++++++++++++++++++++++++------ config/runtime.exs | 19 +++++++++++++++---- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 14435db..090f4e9 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Our philosophy: **software should help people spend less time on administration - 🚧 Sorting & filtering - 🚧 Roles & permissions (e.g. board, treasurer) - ✅ Custom fields (flexible per club needs) -- ✅ SSO via OIDC (tested with Rauthy) +- ✅ SSO via OIDC (works with Authentik, Rauthy, Keycloak, etc.) - 🚧 Self-service & online application - 🚧 Accessibility, GDPR, usability improvements - 🚧 Email sending @@ -147,7 +147,26 @@ Mila uses OIDC for Single Sign-On. In development, a local **Rauthy** instance i 5. copy client secret to `.env` file 6. abort and run `just run` again -Now you can log in to Mila via OIDC! +Now you can log in to Mila via OIDC! + +### OIDC with other providers (Authentik, Keycloak, etc.) + +Mila works with any OIDC-compliant provider. The internal strategy is named `:rauthy`, but this is just a name — it works with any provider. + +**Important:** The redirect URI must always end with `/auth/user/rauthy/callback`. + +Example for Authentik: +1. Create an OAuth2/OpenID Provider in Authentik +2. Set the redirect URI to: `https://your-domain.com/auth/user/rauthy/callback` +3. Configure environment variables: + ```bash + DOMAIN=your-domain.com # or PHX_HOST=your-domain.com + OIDC_CLIENT_ID=your-client-id + OIDC_BASE_URL=https://auth.example.com/application/o/your-app + OIDC_CLIENT_SECRET=your-client-secret # or use OIDC_CLIENT_SECRET_FILE + ``` + +The `OIDC_REDIRECT_URI` is auto-generated as `https://{DOMAIN}/auth/user/rauthy/callback` if not explicitly set. ## ⚙️ Configuration @@ -210,13 +229,13 @@ For testing the production Docker build locally: # Required variables: SECRET_KEY_BASE= TOKEN_SIGNING_SECRET= - PHX_HOST=localhost + DOMAIN=localhost # or PHX_HOST=localhost - # Optional (have defaults in docker-compose.prod.yml): + # Optional OIDC configuration: # OIDC_CLIENT_ID=mv # OIDC_BASE_URL=http://localhost:8080/auth/v1 - # OIDC_REDIRECT_URI=http://localhost:4001/auth/user/rauthy/callback - # OIDC_CLIENT_SECRET= + # OIDC_CLIENT_SECRET= + # OIDC_REDIRECT_URI is auto-generated as https://{DOMAIN}/auth/user/rauthy/callback # Alternative: Use _FILE variables for Docker secrets (takes priority over regular vars): # SECRET_KEY_BASE_FILE=/run/secrets/secret_key_base diff --git a/config/runtime.exs b/config/runtime.exs index 71138ef..765a884 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -112,12 +112,20 @@ if config_env() == :prod do You can generate one by calling: mix phx.gen.secret """) - host = System.get_env("PHX_HOST") || raise "Please define the PHX_HOST environment variable." + # PHX_HOST or DOMAIN can be used to set the host for the application. + # DOMAIN is commonly used in deployment environments (e.g., Portainer templates). + host = + System.get_env("PHX_HOST") || + System.get_env("DOMAIN") || + raise "Please define the PHX_HOST or DOMAIN environment variable." port = String.to_integer(System.get_env("PORT") || "4000") config :mv, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY") - # Rauthy OIDC configuration + # OIDC configuration (works with any OIDC provider: Authentik, Rauthy, Keycloak, etc.) + # Note: The strategy is named :rauthy internally, but works with any OIDC provider. + # The redirect_uri callback path is always /auth/user/rauthy/callback regardless of provider. + # # Supports OIDC_CLIENT_SECRET or OIDC_CLIENT_SECRET_FILE for Docker secrets. # OIDC_CLIENT_SECRET is required only if OIDC is being used (indicated by explicit OIDC env vars). oidc_base_url = System.get_env("OIDC_BASE_URL") @@ -134,12 +142,15 @@ if config_env() == :prod do get_env_or_file.("OIDC_CLIENT_SECRET", nil) end + # Build redirect_uri: use OIDC_REDIRECT_URI if set, otherwise build from host. + # Uses HTTPS since production runs behind TLS termination. + default_redirect_uri = "https://#{host}/auth/user/rauthy/callback" + config :mv, :rauthy, client_id: oidc_client_id || "mv", base_url: oidc_base_url || "http://localhost:8080/auth/v1", client_secret: client_secret, - redirect_uri: - System.get_env("OIDC_REDIRECT_URI") || "http://#{host}:#{port}/auth/user/rauthy/callback" + redirect_uri: System.get_env("OIDC_REDIRECT_URI") || default_redirect_uri # Token signing secret from environment variable # This overrides the placeholder value set in prod.exs From e03693ada541982ab2670920a9ebeed20f55adf1 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 3 Dec 2025 20:51:26 +0100 Subject: [PATCH 3/6] style: fix formatting --- config/runtime.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/config/runtime.exs b/config/runtime.exs index 765a884..06a2cd8 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -118,6 +118,7 @@ if config_env() == :prod do System.get_env("PHX_HOST") || System.get_env("DOMAIN") || raise "Please define the PHX_HOST or DOMAIN environment variable." + port = String.to_integer(System.get_env("PORT") || "4000") config :mv, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY") From 613a5f2643a8b404098b0c28a10a03d8daa98869 Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 3 Dec 2025 21:51:12 +0100 Subject: [PATCH 4/6] feat: support email scope to retrieve oidc info --- lib/accounts/user.ex | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/accounts/user.ex b/lib/accounts/user.ex index 749740d..3b7e80b 100644 --- a/lib/accounts/user.ex +++ b/lib/accounts/user.ex @@ -69,7 +69,7 @@ defmodule Mv.Accounts.User do # Default actions for framework/tooling integration: # - :read -> Standard read used across the app and by admin tooling. # - :destroy-> Standard delete used by admin tooling and maintenance tasks. - # + # # NOTE: :create is INTENTIONALLY excluded from defaults! # Using a default :create would bypass email-synchronization logic. # Always use one of these explicit create actions instead: @@ -185,7 +185,9 @@ defmodule Mv.Accounts.User do oidc_user_info = Ash.Changeset.get_argument(changeset, :oidc_user_info) # Get the new email from OIDC user_info - new_email = Map.get(oidc_user_info, "preferred_username") + # Support both "email" (standard OIDC) and "preferred_username" (Rauthy) + new_email = + Map.get(oidc_user_info, "email") || Map.get(oidc_user_info, "preferred_username") changeset |> Ash.Changeset.change_attribute(:oidc_id, oidc_id) @@ -239,8 +241,11 @@ defmodule Mv.Accounts.User do change fn changeset, _ctx -> user_info = Ash.Changeset.get_argument(changeset, :user_info) + # Support both "email" (standard OIDC like Authentik, Keycloak) and "preferred_username" (Rauthy) + email = user_info["email"] || user_info["preferred_username"] + changeset - |> Ash.Changeset.change_attribute(:email, user_info["preferred_username"]) + |> Ash.Changeset.change_attribute(:email, email) |> Ash.Changeset.change_attribute(:oidc_id, user_info["sub"] || user_info["id"]) end From 9cda832b82bf79307e65d293860f9ba5ad531e0b Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 3 Dec 2025 22:02:23 +0100 Subject: [PATCH 5/6] fix: request scopes email and profile --- lib/accounts/user.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/accounts/user.ex b/lib/accounts/user.ex index 3b7e80b..dbc62b2 100644 --- a/lib/accounts/user.ex +++ b/lib/accounts/user.ex @@ -54,6 +54,9 @@ defmodule Mv.Accounts.User do auth_method :client_secret_jwt code_verifier true + # Request email and profile scopes from OIDC provider (required for Authentik, Keycloak, etc.) + authorization_params scope: "openid email profile" + # id_token_signed_response_alg "EdDSA" #-> https://git.local-it.org/local-it/mitgliederverwaltung/issues/87 end From 32216cd4e3d612f7aec0ef526c1878175e9c0d31 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 3 Dec 2025 21:23:42 +0000 Subject: [PATCH 6/6] chore(deps): update renovate/renovate docker tag to v42 --- .drone.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.drone.yml b/.drone.yml index 483a08a..fb74239 100644 --- a/.drone.yml +++ b/.drone.yml @@ -166,7 +166,7 @@ environment: steps: - name: renovate - image: renovate/renovate:41.173 + image: renovate/renovate:42.34 environment: RENOVATE_CONFIG_FILE: "renovate_backend_config.js" RENOVATE_TOKEN: