This release is a pre-release and may not be stable for production use.
reflex-magic-link-auth
Generate and verify "magic link" one time passwords for user authentication without complex registration flows.
Installation
pip install reflex-magic-link-auth
Usage
See
magic_link_auth_demo/magic_link_auth_demo.py
for a complete example.
1. Collect the User email
You can use a simple form with a single input field and button, like the example, or present a form prompting for more information, such as a name, address, zip code, etc. Any additional data should be associated with the provided email as the main key for the account.
2. Substate from MagicLinkAuthState
The substate which handles the authentication form submission should be
a substate of reflex_magic_link_auth.MagicLinkAuthState (alternatively, it
may get an instance of this state via .get_state API).
3. Generate the OTP
When the user submits the form, generate a one time password by calling
._generate_otp and providing the email address.
This function returns a 2-tuple:
- The latest record associated with the email address
- The one time password in plaintext
If the record is None, then the email address was invalid, or some other problem occurred (ensure database migration has been applied).
If the record is returned, but the OTP is None, then the user has exceeded the configured rate limit and cannot receive a new token for a while.
4. Send the Magic Link
Either on page on_load or some component on_mount should trigger
reflex_magic_link_auth.MagicLinkAuthState.get_base_url to ensure the state
knows the correct frontend URL when formatting the magic links.
Pass the record and otp to
reflex_magic_link_auth.MagicLinkAuthState._get_magic_link to get a URL that,
when accessed will log the user in to the app.
While this component contains an example mailgun provider, generally it is up to you to actually email the link to the user.
5. User Accesses the Magic Link
The user clicks the link in their email, and the page mounted at
reflex_magic_link_auth.constants.AUTH_ROUTE will validate the token and
redirect to the URL specified in the query param redir.
6. Verifying Access
Any event handlers which depend on user session validity should check the computed var
reflex_magic_link_auth.MagicLinkAuthState.session_is_valid to determine if the user is
logged in and the session has not expired.
A persistent external identifier hashed over the email address is provided at
reflex_magic_link_auth.MagicLinkAuthState.auth_session.persistent_id. When interoperating
with other user information systems, this ID can be used to uniquely identify a user
originating from reflex-magic-link-auth.
7. Logout
To log the user out, trigger the event handler
reflex_magic_link_auth.MagicLinkAuthState.logout.
Configuration
The values in reflex_magic_link_auth.constants can each be overridden by an
environment variable, so a deployment can tune them without a code change:
| Environment variable | Constant | Default |
|---|---|---|
MAGIC_LINK_AUTH_ROUTE |
AUTH_ROUTE |
/magic-link-auth |
MAGIC_LINK_AUTH_OTP_EXPIRATION_SECONDS |
DEFAULT_OTP_EXPIRATION_DELTA |
1800 (30 minutes) |
MAGIC_LINK_AUTH_SESSION_EXPIRATION_SECONDS |
DEFAULT_AUTH_SESSION_EXPIRATION_DELTA |
604800 (7 days) |
MAGIC_LINK_AUTH_OTP_RATE_LIMIT |
DEFAULT_OTP_RATE_LIMIT |
5 |
export MAGIC_LINK_AUTH_OTP_EXPIRATION_SECONDS=300 # 5 minute magic links
export MAGIC_LINK_AUTH_OTP_RATE_LIMIT=3
MAGIC_LINK_AUTH_OTP_EXPIRATION_SECONDS sets both how long an OTP stays valid
and the window the per-email and per-IP rate limits are counted over.
The environment is read once, when the package is imported. AUTH_ROUTE is
consumed at import time to register the page, so the variables must be set
before your app imports reflex_magic_link_auth — which is the normal case for
a process started with them already in place.
A variable that is set to something unusable — a route that is not an absolute
path, a non-numeric duration, a rate limit below 1 — raises ValueError on
import instead of falling back to the default. These values bound how long a
credential lives and how often one can be requested, so a typo should stop the
app rather than quietly weaken it. Setting a variable to an empty string means
"no opinion" and keeps the default.
Values passed explicitly still win: _generate_otp takes expiration_delta
and rate_limit, and MagicLinkAuthSession.from_record takes
expiration_delta. The constants are only the fallback.
Changelog
See CHANGELOG.md.
Contributing
Every pull request that changes custom_components/ needs a news fragment — a
short markdown file under news/, named <pr-number>.<type>.md, written for
someone reading release notes:
uvx --from "reflex-release @ git+https://github.com/reflex-dev/reflex@1613d415c8d443cdd81d097fd08ae02213dfe04f#subdirectory=packages/reflex-release" \
reflex-release create 123.bugfix.md
The types are breaking, deprecation, feature, bugfix, performance,
docs and misc. Before the PR number is known, name the file
+something.bugfix.md and rename it later. The skip-changelog label waives
the requirement for changes that are not user-facing.
Do not edit CHANGELOG.md by hand: a new version heading on main is what
triggers a publish, so CI rejects headings that were not written by the release
workflow.
Releasing
Releases are changelog-driven, via reflex-release.
- Run Dispatch release from the Actions tab and pick an action
(
release-patch/-minor/-major,release-post, or one of the prerelease actions). It runs towncrier overnews/, writes the newCHANGELOG.mdsection, and opens a pull request. - Merge that pull request. The push to
mainis what publishes: Release from changelog finds the changelog version that has no git tag, builds it, and waits for approval on thepypienvironment before uploading. - After a successful upload the tag and GitHub release are created, and
Deploy demo app redeploys
magic_link_auth_demoagainst the new version.
Because tags are only created after a successful upload, a failed release is retried by pushing a fix on top of the changelog bump — there is nothing to clean up.
Upgrading the release tooling is a cli-command bump in pyproject.toml
followed by reflex-release sync; the pull-request check fails while the
generated workflows are out of date.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file reflex_magic_link_auth-0.2.2a1.tar.gz.
File metadata
- Download URL: reflex_magic_link_auth-0.2.2a1.tar.gz
- Upload date:
- Size: 33.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10f44b898bfebaf623a0eef22d35874c1512f7f80a3cc625fa0184a9478e2593
|
|
| MD5 |
3524dad5fb17a2fa5aa809a383c546de
|
|
| BLAKE2b-256 |
fcadf8c0f3597332a31aec182ab257c80edeb98fbf9becb16b6491b1bf94db8d
|
File details
Details for the file reflex_magic_link_auth-0.2.2a1-py3-none-any.whl.
File metadata
- Download URL: reflex_magic_link_auth-0.2.2a1-py3-none-any.whl
- Upload date:
- Size: 12.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
071f1492cc2b5c92e63c6dfac840719396306803098daea85d5a7bd4c8fa9955
|
|
| MD5 |
c8cb574c545f830caea8c47595d8e905
|
|
| BLAKE2b-256 |
adeaeaf5da0dc4cffe853132a1d35a237a92d01a7dcf7a15eea83746895a8401
|