Skip to content

Commit 87cdbad

Browse files
authored
Allow Magic Link sign in to register new user (#9007)
Adds a configuration property to the provider config that will have the sign-in flow act as a sign-up flow if set to true.
1 parent 4785bb5 commit 87cdbad

File tree

6 files changed

+417
-15
lines changed

6 files changed

+417
-15
lines changed

edb/buildmeta.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
# The merge conflict there is a nice reminder that you probably need
5858
# to write a patch in edb/pgsql/patches.py, and then you should preserve
5959
# the old value.
60-
EDGEDB_CATALOG_VERSION = 2025_08_20_00_00
60+
EDGEDB_CATALOG_VERSION = 2025_09_09_00_00
6161
EDGEDB_MAJOR_VERSION = 8
6262

6363

edb/lib/ext/auth.edgeql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,10 @@ CREATE EXTENSION PACKAGE auth VERSION '1.0' {
378378
create required property verification_method: ext::auth::VerificationMethod {
379379
set default := ext::auth::VerificationMethod.Link;
380380
};
381+
382+
create required property auto_signup: std::bool {
383+
set default := false;
384+
};
381385
};
382386

383387
create scalar type ext::auth::FlowType extending std::enum<PKCE, Implicit>;

edb/server/protocol/auth_ext/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class MagicLinkProviderConfig(ProviderConfig):
104104
name: Literal["builtin::local_magic_link"]
105105
token_time_to_live: statypes.Duration
106106
verification_method: VerificationMethod
107+
auto_signup: bool
107108

108109

109110
@dataclass

edb/server/protocol/auth_ext/http.py

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,6 +1464,7 @@ async def handle_magic_link_email(
14641464
) -> None:
14651465
data = self._get_data_from_request(request)
14661466
email: str | None = None
1467+
return_data: dict[str, Any] = {}
14671468

14681469
try:
14691470
_check_keyset(data, {"email"})
@@ -1483,22 +1484,45 @@ async def handle_magic_link_email(
14831484
email_factor = await magic_link_client.get_email_factor_by_email(
14841485
email
14851486
)
1487+
is_signup = False
14861488
if email_factor is None:
1487-
logger.error(
1488-
f"Cannot send magic link email: no email factor found for "
1489-
f"email={email}"
1490-
)
1491-
await auth_emails.send_fake_email(self.tenant)
1492-
if magic_link_client.provider.verification_method == "Code":
1493-
return_data = {
1494-
"code": "true",
1495-
"email": email,
1496-
}
1489+
if magic_link_client.provider.auto_signup:
1490+
# Auto-signup is enabled, create a new user
1491+
is_signup = True
1492+
email_factor = await magic_link_client.register(
1493+
email=email,
1494+
)
1495+
await self._maybe_send_webhook(
1496+
webhook.IdentityCreated(
1497+
event_id=str(uuid.uuid4()),
1498+
timestamp=datetime.datetime.now(datetime.timezone.utc),
1499+
identity_id=email_factor.identity.id,
1500+
)
1501+
)
1502+
await self._maybe_send_webhook(
1503+
webhook.EmailFactorCreated(
1504+
event_id=str(uuid.uuid4()),
1505+
timestamp=datetime.datetime.now(datetime.timezone.utc),
1506+
identity_id=email_factor.identity.id,
1507+
email_factor_id=email_factor.id,
1508+
)
1509+
)
14971510
else:
1498-
return_data = {
1499-
"email_sent": email,
1500-
}
1501-
else:
1511+
logger.error(
1512+
"Cannot send magic link email: no email factor found "
1513+
f"for email={email}"
1514+
)
1515+
await auth_emails.send_fake_email(self.tenant)
1516+
if magic_link_client.provider.verification_method == "Code":
1517+
return_data = {
1518+
"code": "true",
1519+
"email": email,
1520+
}
1521+
else:
1522+
return_data = {
1523+
"email_sent": email,
1524+
}
1525+
if email_factor is not None:
15021526
identity_id = email_factor.identity.id
15031527
if magic_link_client.provider.verification_method == "Code":
15041528
code, otc_id = await otc.create(
@@ -1530,6 +1554,8 @@ async def handle_magic_link_email(
15301554
"code": "true",
15311555
"email": email,
15321556
}
1557+
if is_signup:
1558+
return_data["signup"] = "true"
15331559
else:
15341560
_check_keyset(
15351561
data,
@@ -1587,6 +1613,8 @@ async def handle_magic_link_email(
15871613
return_data = {
15881614
"email_sent": email,
15891615
}
1616+
if is_signup:
1617+
return_data["signup"] = "true"
15901618

15911619
if allowed_redirect_to:
15921620
return self._do_redirect(

edb/server/protocol/auth_ext/magic_link.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def _get_provider(self) -> config.MagicLinkProviderConfig:
6363
name=cfg.name,
6464
token_time_to_live=cfg.token_time_to_live,
6565
verification_method=cfg.verification_method,
66+
auto_signup=cfg.auto_signup,
6667
)
6768

6869
raise errors.MissingConfiguration(

0 commit comments

Comments
 (0)