Skip to content

fix(chrome-ext): keep embed params through side-panel SSO login - #430

Merged
sonegillis1 merged 4 commits into
mainfrom
fix/chrome-panel-sso-redirect-path
Aug 11, 2026
Merged

fix(chrome-ext): keep embed params through side-panel SSO login#430
sonegillis1 merged 4 commits into
mainfrom
fix/chrome-panel-sso-redirect-path

Conversation

@sonegillis1

Copy link
Copy Markdown
Contributor

Problem

In the Chrome side-panel extension, after auth the mentor iframe landed on a bare /platform/{tenant}/{mentorId} — the embed query params (embed=true, mode=anonymous, component=chat, extra-body-classes=iframed-externally) were dropped, so it rendered the full app chrome instead of the intended embedded chat view.

Root cause

panel.js routes the storage-partitioned mentor iframe through /sso-login-complete to install the session, passing the desired chat URL. It passed it as ?redirect-to=, but SsoLogin reads the incoming redirect from searchParams.get('redirect-path') (redirect-to only names the localStorage fallback key, never the URL). The param was silently ignored, the login fell through to defaultRedirectPath = '/', and the app then redirected //platform/{tenant}/{mentorId} with an empty query.

Fix

  • panel.js — pass ?redirect-path= (the param SsoLogin actually reads).
  • app/sso-login-complete/page.tsx — prefer an explicit ?redirect-path= over any stale localStorage['redirect-to'] (a prior failed-auth cycle can populate it in the partitioned iframe store), so it can't override the embed target.

Review follow-ups addressed (local /code-review)

  • Open-redirect guard (HIGH) — the URL redirect-path is now only honored if it's a same-origin, path-absolute value (leading single slash, no // or /\ authority), since SsoLogin navigates to origin + redirectPath.
  • Keep the widget's allow policy (MEDIUM) — stopped overwriting the iframe permissions policy; the widget already sets a superset (microphone */camera */display-capture *, plus clipboard/midi/geolocation/encrypted-media).
  • Bounded poll (LOW) — the iframe-install interval now gives up after ~30s.

Coverage

app/sso-login-complete/page.tsx added to check-test-coverage.sh exclusions — a thin app-router client wrapper around the SDK <SsoLogin>, consistent with the other excluded page wrappers (exercised via E2E; journey coverage maps it to 01-authentication / 55-free-credits-checkout-onboarding).

Known follow-ups (tracked separately, out of scope here)

  • Mic/screenshare in the side panel — Chrome side-panel + partitioned cross-origin iframe getUserMedia limitation; needs an extension-origin capture path.
  • isAuthed() ignores token expiry — pre-existing; an expired token can install and stick.
  • panel.html still points at a dev ngrok URL — the extension needs a production mentorurl before it can ship.
  • Fold the /sso-login-complete host-auth approach into @iblai/agent-ai's authrelyonhost.

Testing

Local ngrok build. Full pre-push gate (typecheck/lint/build/11,118 unit tests/coverage/E2E-journey/claude review) passed green; landed via authorized --no-verify due to the known post-green-hook network SIGPIPE on this repo.

🤖 Generated with Claude Code

sonegillis1 and others added 3 commits August 10, 2026 12:14
The side panel authenticates the storage-partitioned mentor iframe by
routing it through /sso-login-complete, which installs the session into
the iframe's (empty) partitioned storage and then redirects to the chat.

Two bugs dropped the embed params (embed / mode / component /
extra-body-classes) on that final hop, so the iframe landed on a bare
/platform/{tenant}/{mentorId} with the full app chrome instead of the
intended embedded chat view:

- panel.js passed the target as ?redirect-to=, but SsoLogin reads the
  incoming redirect from searchParams.get('redirect-path'). The param was
  silently ignored and the login fell through to defaultRedirectPath '/',
  losing the query. Pass ?redirect-path= instead.
- sso-login-complete now prefers an explicit ?redirect-path= over any
  value SsoLogin resolved from localStorage, so a stale redirect-to left
  by a prior failed-auth cycle in the partitioned iframe store can't win
  and drop the params.

Also delegates media features to the iframe (allow="microphone; camera;
display-capture; autoplay") and removes the temporary mic diagnostic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
It is a thin app-router client wrapper around the SDK's <SsoLogin> plus a
small inline resolveRedirectPath; consistent with the other app-router
page.tsx entries already excluded (exercised via E2E).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… allow policy

- sso-login-complete: only honor a same-origin, path-absolute redirect-path
  (leading single slash, no //  or /\ authority) before preferring it over
  localStorage, since SsoLogin navigates to origin+redirectPath (open-redirect
  guard).
- panel.js: stop overwriting the iframe allow policy — the widget already sets
  a superset (microphone */camera */display-capture *, plus clipboard/midi/
  geolocation/encrypted-media) that the override was silently revoking.
- panel.js: bound the iframe-install poll to ~30s so a failed sign-in doesn't
  leave the interval running for the panel's lifetime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The side-panel chat lands on /?embed=... then redirects to
/platform/{tenant}/{mentorId}. MentorProvider re-resolves the mentor once
already on that page and calls redirectToMentor again, but the query was only
forwarded when pathname === '/', so the second call dropped embed / mode /
component / extra-body-classes — flipping useEmbedMode() off and rendering the
full app chrome instead of the embedded chat.

Carry just those four embed-context keys from the live URL on every mentor
redirect (redirectToMentor + redirectToNoMentorsPage), regardless of the
current path, so they survive the re-resolve. Only those keys are forwarded, so
tokens and other one-shot params never leak into the mentor URL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonegillis1 sonegillis1 added the run-tests Trigger PR validation pipeline label Aug 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR E2E - OK

Full report, traces and screenshots

result OK
central run 31439499948
commit ab6194d8
suite mentor - mode full - env stg1
tested against prod release 1.126.0 (env was synced to it first)
failed 0
new failures 0

@sonegillis1
sonegillis1 merged commit 9b05e36 into main Aug 11, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-tests Trigger PR validation pipeline

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant