refactor(streams): replace STREAMS_SECRET with session-based auth#1360
Conversation
Replace the shared static STREAMS_SECRET with per-user session token validation. The streams server now queries the auth.sessions table directly via @superset/db to validate Bearer tokens, providing per-user identity, automatic expiration, and revocation support.
📝 WalkthroughWalkthroughThis PR replaces a shared STREAMS_SECRET authentication model with a database-backed session token system. It updates CI/CD workflows to use DATABASE_URL, removes static secret setup from build configuration, and converts the Streams server to validate tokens against a database table instead of checking a pre-configured secret. The desktop client now dynamically loads encrypted tokens at runtime. Changes
Sequence Diagram(s)sequenceDiagram
participant Desktop as Desktop Client
participant Token as Token Storage<br/>(encrypted file)
participant Server as Streams Server
participant DB as Database<br/>(auth.sessions)
Desktop->>Token: loadToken()
Token-->>Desktop: encrypted token
Desktop->>Server: /v1/* request<br/>+ Bearer token
Server->>DB: SELECT * FROM sessions<br/>WHERE token = ?
DB-->>Server: {token, userId, expires}
alt Token valid & not expired
Server->>Server: Attach userId to context
Server-->>Desktop: 200 + response data
else Token invalid/expired
Server-->>Desktop: 401 Unauthorized
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @.github/workflows/deploy-preview.yml:
- Around line 137-140: The step named "Load database URL" is leaving variable
expansions unquoted; update the echo to quote the DATABASE_URL expansion and the
GITHUB_ENV target to prevent word splitting/globbing: change the echo line so it
uses the $DATABASE_URL variable inside double quotes (e.g. echo
"DATABASE_URL=$DATABASE_URL" with the expansion quoted) and quote $GITHUB_ENV in
the redirection (>> "$GITHUB_ENV"); reference the step name "Load database URL"
and the variables $DATABASE_URL and $GITHUB_ENV when making the change.
In `@apps/streams/src/server.ts`:
- Around line 1-3: Remove the redundant dotenv initialization in client.ts:
delete the config({ path: ".env", quiet: true }) call in
packages/db/src/client.ts (the one before importing env.ts), since env.ts
already calls config(...) with the absolute monorepo path; keep the import of
env.ts and the db singleton logic intact so DATABASE_URL resolution continues to
come from env.ts.
🧹 Nitpick comments (3)
apps/desktop/src/lib/trpc/routers/ai-chat/utils/session-manager/session-manager.ts (1)
33-42: Stale token risk in long-running agent sessions.
buildProxyHeaders()is called once instartAgent(Line 265), and the resultingheadersobject is reused for all subsequentonChunkPOSTs and thefinallycleanup requests. If the session token is rotated or invalidated mid-execution, those downstream requests will silently fail with 401.Given the 30-day expiry this is unlikely in practice, but if token rotation is ever shortened (or if the user signs out mid-run), this could cause hard-to-diagnose failures. Consider re-fetching headers for the
finallyblock at minimum, since that's the critical path for marking the message as complete.docs/replace-streams-secret-with-session-auth.md (1)
27-27: Add a language identifier to the fenced code block to satisfy markdownlint (MD040).Since this is a text diagram, use
```textto silence the warning.apps/streams/src/server.ts (1)
67-86: DB query on every request — consider caching for high-frequency endpoints.The
onChunkcallback in the desktop session manager fires a POST to/v1/sessions/:id/chunksfor every streaming chunk, and each of those hits this middleware, triggering a DB round-trip. Under heavy streaming this could add meaningful latency and DB load.Consider a short-lived in-memory cache (e.g., LRU with 30–60s TTL) keyed by token → userId. The 30-day session expiry and the fact that revocation is not instantaneous anyway make a brief cache safe.
| - name: Load database URL | ||
| run: | | ||
| source database-status.env | ||
| echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV |
There was a problem hiding this comment.
Quote the variable to prevent word splitting.
Per the static analysis hint (SC2086), $DATABASE_URL should be double-quoted to prevent globbing and word splitting, especially since connection strings can contain special characters.
Proposed fix
- name: Load database URL
run: |
source database-status.env
- echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV
+ echo "DATABASE_URL=${DATABASE_URL}" >> "$GITHUB_ENV"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Load database URL | |
| run: | | |
| source database-status.env | |
| echo "DATABASE_URL=$DATABASE_URL" >> $GITHUB_ENV | |
| - name: Load database URL | |
| run: | | |
| source database-status.env | |
| echo "DATABASE_URL=${DATABASE_URL}" >> "$GITHUB_ENV" |
🧰 Tools
🪛 actionlint (1.7.10)
[error] 138-138: shellcheck reported issue in this script: SC2086:info:2:38: Double quote to prevent globbing and word splitting
(shellcheck)
🤖 Prompt for AI Agents
In @.github/workflows/deploy-preview.yml around lines 137 - 140, The step named
"Load database URL" is leaving variable expansions unquoted; update the echo to
quote the DATABASE_URL expansion and the GITHUB_ENV target to prevent word
splitting/globbing: change the echo line so it uses the $DATABASE_URL variable
inside double quotes (e.g. echo "DATABASE_URL=$DATABASE_URL" with the expansion
quoted) and quote $GITHUB_ENV in the redirection (>> "$GITHUB_ENV"); reference
the step name "Load database URL" and the variables $DATABASE_URL and
$GITHUB_ENV when making the change.
| import { db } from "@superset/db"; | ||
| import { sessions } from "@superset/db/schema/auth"; | ||
| import { and, eq, gt } from "drizzle-orm"; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Locate packages/db directory structure
cd apps/streams || cd . 2>/dev/null
find . -path "*/packages/db*" -type d 2>/dev/null | head -5Repository: superset-sh/superset
Length of output: 46
🏁 Script executed:
#!/bin/bash
# Search for database client initialization in packages/db
fd -t f '\.(ts|js)$' packages/db --exec head -50 {} \; 2>/dev/null | head -100Repository: superset-sh/superset
Length of output: 2334
🏁 Script executed:
#!/bin/bash
# Look for DATABASE_URL references in packages/db
rg 'DATABASE_URL' packages/db 2>/dev/null || echo "No matches found"Repository: superset-sh/superset
Length of output: 415
🏁 Script executed:
#!/bin/bash
# Check the structure of packages/db
ls -la packages/db/ 2>/dev/null || echo "Directory not found at packages/db"Repository: superset-sh/superset
Length of output: 484
🏁 Script executed:
#!/bin/bash
# Get the full content of env.ts in packages/db
cat packages/db/src/env.tsRepository: superset-sh/superset
Length of output: 554
🏁 Script executed:
#!/bin/bash
# Check if there's any dotenv config or initialization in packages/db
rg 'config|dotenv' packages/db/src/ -A 2 -B 2Repository: superset-sh/superset
Length of output: 1423
Remove redundant dotenv config from client.ts; DATABASE_URL resolution is already handled correctly by env.ts.
The db singleton correctly reads DATABASE_URL from the streams server's environment because packages/db/src/env.ts uses an absolute path to load .env from the monorepo root: config({ path: path.resolve(__dirname, "../../../.env"), quiet: true }). However, packages/db/src/client.ts has a redundant config({ path: ".env", quiet: true }) with a relative path that is unnecessary and creates confusion. Remove this line since env.ts is imported immediately after and handles the environment setup correctly.
🤖 Prompt for AI Agents
In `@apps/streams/src/server.ts` around lines 1 - 3, Remove the redundant dotenv
initialization in client.ts: delete the config({ path: ".env", quiet: true })
call in packages/db/src/client.ts (the one before importing env.ts), since
env.ts already calls config(...) with the absolute monorepo path; keep the
import of env.ts and the db singleton logic intact so DATABASE_URL resolution
continues to come from env.ts.
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
Summary
STREAMS_SECRETwith per-user session token validation via direct DB query againstauth.sessionstableloadToken()) instead of using a static env varSTREAMS_SECRETfrom all source code, CI/CD pipelines, and setup scriptsChanges
Streams server (
apps/streams)src/server.ts: Replace string-comparison middleware with Drizzle query — validates Bearer token againstauth.sessions(checks token + expiry), attachesuserIdto Hono contextsrc/env.ts: ReplaceSTREAMS_SECRETwithDATABASE_URLsrc/index.ts: RemoveauthTokenfromcreateServer()callpackage.json: Add@superset/dbanddrizzle-ormdependenciesDockerfile: Includepackages/dbin build and runtime stagesDesktop (
apps/desktop)session-manager.ts: MakebuildProxyHeaders()async usingloadToken()instead of static secret;awaitat all 5 call sitesai-chat/index.ts: MakegetConfigasync, return session token fromloadToken()env.main.ts: RemoveSTREAMS_SECRETfrom schema and runtimeEnvCI/CD & config cleanup
turbo.jsonc: RemoveSTREAMS_SECRETfromglobalEnvci.yml: RemoveSTREAMS_SECRETenv var and TODO commentdeploy-preview.yml: ReplaceSTREAMS_SECRETwithDATABASE_URL; addneeds: deploy-databasewith artifact downloaddeploy-production.yml: ReplaceSTREAMS_SECRETwithDATABASE_URLinflyctl secrets set.superset/setup.sh: Removestep_setup_streams()andSTREAMS_SECRETenv outputTest Plan
grep -r STREAMS_SECRETreturns only docs files (no source code matches)bun turbo run typecheck --filter=@superset/streamspassesbun turbo run typecheck --filter=@superset/desktoppassesSummary by CodeRabbit
Release Notes
Refactor
Chores