diff --git a/synapse/config/oidc.py b/synapse/config/oidc.py
index fc95912d9b..5d571651cb 100644
--- a/synapse/config/oidc.py
+++ b/synapse/config/oidc.py
@@ -183,7 +183,8 @@ class OIDCConfig(Config):
# localpart_template: Jinja2 template for the localpart of the MXID.
# If this is not set, the user will be prompted to choose their
# own username (see the documentation for the
- # 'sso_auth_account_details.html' template).
+ # 'sso_auth_account_details.html' template). This template can
+ # use the 'localpart_from_email' filter.
#
# confirm_localpart: Whether to prompt the user to validate (or
# change) the generated localpart (see the documentation for the
diff --git a/synapse/handlers/oidc.py b/synapse/handlers/oidc.py
index d98659edc7..724b9cfcb4 100644
--- a/synapse/handlers/oidc.py
+++ b/synapse/handlers/oidc.py
@@ -45,6 +45,7 @@ from synapse.types import JsonDict, UserID, map_username_to_mxid_localpart
from synapse.util import Clock, json_decoder
from synapse.util.caches.cached_call import RetryOnExceptionCachedCall
from synapse.util.macaroons import get_value_from_macaroon, satisfy_expiry
+from synapse.util.templates import _localpart_from_email_filter
if TYPE_CHECKING:
from synapse.server import HomeServer
@@ -1308,6 +1309,11 @@ def jinja_finalize(thing: Any) -> Any:
env = Environment(finalize=jinja_finalize)
+env.filters.update(
+ {
+ "localpart_from_email": _localpart_from_email_filter,
+ }
+)
@attr.s(slots=True, frozen=True, auto_attribs=True)
diff --git a/synapse/util/templates.py b/synapse/util/templates.py
index 12941065ca..fb758b7180 100644
--- a/synapse/util/templates.py
+++ b/synapse/util/templates.py
@@ -64,6 +64,7 @@ def build_jinja_env(
{
"format_ts": _format_ts_filter,
"mxc_to_http": _create_mxc_to_http_filter(config.server.public_baseurl),
+ "localpart_from_email": _localpart_from_email_filter,
}
)
@@ -112,3 +113,7 @@ def _create_mxc_to_http_filter(
def _format_ts_filter(value: int, format: str) -> str:
return time.strftime(format, time.localtime(value / 1000))
+
+
+def _localpart_from_email_filter(address: str) -> str:
+ return address.rsplit("@", 1)[0]
|