Skip to content

Add signed browser sessions and bound client tokens - #7361

Open
masenf wants to merge 4 commits into
mainfrom
codex/codex/session-token-primitives
Open

masenf wants to merge 4 commits into
mainfrom
codex/codex/session-token-primitives

Conversation

@masenf

@masenf masenf commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Add signed browser sessions and cryptographically bound per-tab client tokens. A client token alone cannot prove ownership of another session. Credentials are bound to the application's name, use HS256 with a pinned algorithm, and validate schema, lifetime, signing-key ID, and audience. Rotation preserves existing tab bindings.

REFLEX_SESSION_SECRET supplies a comma-separated signing-key ring. Without it, workers share an atomically published key in .web/backend/session_secret; initialization preserves it and exported archives exclude it. POSIX files use owner-only permissions; Windows follows inherited directory ACLs. Config exposes a seven-day default TTL and half-TTL refresh interval; enforcement modes are off, warn (default), and enforce.

Rebased on main d02ba5409. Review order: #7361 → #7362 → #7363 → #7364. The earlier #7360 dependency is merged.

Validation: 244 focused session, initialization, export, and locking tests passed. Audience-isolation and persistence regressions fail without their fixes. The full assembled stack passes 12,147 unit tests with 80.15% coverage; see #7364 for integration validation.

Session ownership is intentionally valid for an already established connection; expiry gates HTTP credentials and reconnects. This is not application login or per-session revocation. The review discussion records the rationale.

Related to ENG-12910, ENG-9088.

@masenf
masenf added this pull request to stack #7365 September 30, 2026 00:41
@masenf masenf changed the title codex/codex/session token primitives Add signed browser sessions and bound client tokens Sep 30, 2026
@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Critical impact] Adds session signing and secret management to authentication.

The remaining repository requirements should be satisfied before merging.

Findings

  1. P2 Shared claim keys are repeated ▶

Summary

Adds signed browser sessions, app-bound credentials, per-tab client tokens, signing-key rotation, and configurable lifetimes.

  • Each browser tab gets a token tied to its signed app session.
  • The local session key survives initialization and stays out of app archives.

Reviews (7) · Last reviewed commit: "Keep frontend cleanup locking coverage w..." · Reviewed by Greptile

Comment thread packages/reflex-base/src/reflex_base/session.py
Comment thread packages/reflex-base/src/reflex_base/session.py
Comment thread packages/reflex-base/src/reflex_base/config.py Outdated
@codspeed

codspeed Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ 22 benchmarks spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

✅ 148 untouched benchmarks


Comparing codex/codex/session-token-primitives (44c4b4e) with main (d02ba54)

Open in CodSpeed

@masenf
masenf force-pushed the codex/codex/session-token-primitives branch from 514269c to b7efd10 Compare October 5, 2026 21:24
@linear-code

linear-code Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

ENG-9088

ENG-12910

@masenf
masenf force-pushed the codex/codex/session-token-primitives branch 3 times, most recently from b227f18 to 427f2c0 Compare October 8, 2026 18:36
Base automatically changed from codex/session-cookie-privacy to main October 8, 2026 19:03
@masenf
masenf force-pushed the codex/codex/session-token-primitives branch from 427f2c0 to db30d29 Compare October 8, 2026 19:03
Introduce a stdlib HS256 session codec, environment-only signing keys with rotation, and persistent local secrets excluded from exports. Preserve the local secret during web reinitialization.

Validation: 421 affected tests passed, plus unknown-key diagnostic coverage; Ruff and targeted pyright passed.

Refs: ENG-12910
@masenf
masenf force-pushed the codex/codex/session-token-primitives branch from db30d29 to 44c4b4e Compare October 14, 2026 09:35
Comment thread packages/reflex-base/src/reflex_base/session.py
@masenf
masenf marked this pull request as ready for review October 14, 2026 09:54
@masenf
masenf requested a review from a team as a code owner October 14, 2026 09:54

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 11 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="reflex/utils/frontend_skeleton.py">

<violation number="1" location="reflex/utils/frontend_skeleton.py:471">
P1: This branch follows a symlinked `.web/backend` and removes its target's contents, which can erase files outside the generated web directory during `reflex init`. Guard against symlink traversal and handle the link without modifying its target.</violation>
</file>

<file name="tests/units/reflex_base/test_session.py">

<violation number="1" location="tests/units/reflex_base/test_session.py:421">
P2: This defaults assertion fails whenever either session setting is already present in the test process environment. Clear both variables before constructing the default config so the test remains isolated.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

path_ops.copy_tree(constants.Templates.Dirs.WEB_TEMPLATE, str(web_dir))
if web_dir.exists():
for item in web_dir.iterdir():
if item.name == constants.Dirs.BACKEND and item.is_dir():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: This branch follows a symlinked .web/backend and removes its target's contents, which can erase files outside the generated web directory during reflex init. Guard against symlink traversal and handle the link without modifying its target.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At reflex/utils/frontend_skeleton.py, line 471:

<comment>This branch follows a symlinked `.web/backend` and removes its target's contents, which can erase files outside the generated web directory during `reflex init`. Guard against symlink traversal and handle the link without modifying its target.</comment>

<file context>
@@ -464,7 +466,17 @@ def initialize_web_directory():
-        path_ops.copy_tree(constants.Templates.Dirs.WEB_TEMPLATE, str(web_dir))
+        if web_dir.exists():
+            for item in web_dir.iterdir():
+                if item.name == constants.Dirs.BACKEND and item.is_dir():
+                    for backend_file in item.iterdir():
+                        if backend_file.name != SESSION_SECRET_FILENAME:
</file context>

monkeypatch: The environment override fixture.
"""
monkeypatch.setenv("REFLEX_SESSION_SECRET", SECRET.decode())
config = Config(app_name="test")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This defaults assertion fails whenever either session setting is already present in the test process environment. Clear both variables before constructing the default config so the test remains isolated.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At tests/units/reflex_base/test_session.py, line 421:

<comment>This defaults assertion fails whenever either session setting is already present in the test process environment. Clear both variables before constructing the default config so the test remains isolated.</comment>

<file context>
@@ -0,0 +1,446 @@
+        monkeypatch: The environment override fixture.
+    """
+    monkeypatch.setenv("REFLEX_SESSION_SECRET", SECRET.decode())
+    config = Config(app_name="test")
+    assert config.session_token_ttl == 604800
+    assert config.session_token_refresh_interval is None
</file context>
Suggested change
config = Config(app_name="test")
monkeypatch.delenv("REFLEX_SESSION_TOKEN_TTL", raising=False)
monkeypatch.delenv("REFLEX_SESSION_TOKEN_REFRESH_INTERVAL", raising=False)
config = Config(app_name="test")

@masenf masenf mentioned this pull request Oct 20, 2026
10 of 13 tasks
@masenf masenf added roadmap https://github.com/reflex-dev/reflex/issues/2727 security labels Oct 23, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

roadmap https://github.com/reflex-dev/reflex/issues/2727 security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant