fix: repair invite flow — URL prefix + registration UI#81
fix: repair invite flow — URL prefix + registration UI#81SrikanthAlva wants to merge 9 commits intoemdash-cms:mainfrom
Conversation
c02d284 to
8c6f151
Compare
The invite system had two compounding bugs making it completely
non-functional:
1. The invite URL dropped the /_emdash/ prefix because
`new URL("/api/auth/invite/accept", baseUrl)` treats the leading
slash as an absolute path, discarding any path component in baseUrl.
Fixed by using string concatenation: `new URL(`${baseUrl}/admin/invite/accept`)`.
2. There was no UI for invited users to complete registration. The
invite link now points directly to a new admin SPA page
(/_emdash/admin/invite/accept) that validates the token, shows the
user's email and role, and drives passkey registration via the
existing /auth/invite/complete endpoint.
3. The auth middleware blocked unauthenticated access to the invite
accept page. Added /_emdash/admin/invite/accept (and /signup) to the
public admin route bypass list so invited users can reach the page
without an existing session.
Changes:
- packages/auth/src/invite.ts: fix URL construction, point to admin UI
- packages/core/src/astro/middleware/auth.ts: allow unauthenticated
access to invite accept and signup admin pages
- packages/core/tests/unit/auth/invite.test.ts: add regression test
for baseUrl with path prefix
- packages/admin/src/components/InviteAcceptPage.tsx: new invite
acceptance page (modeled after SignupPage)
- packages/admin/src/lib/api/users.ts: add validateInviteToken and
completeInviteSignup client functions
- packages/admin/src/lib/api/index.ts: re-export new functions
- packages/admin/src/router.tsx: register /invite/accept route
Closes emdash-cms#67
Made-with: Cursor
The invite page was incorrectly using the setup/admin endpoint to generate passkey registration options, which fails with "Setup already complete" after initial setup. This adds a dedicated /api/auth/invite/register-options endpoint that validates the invite token and generates passkey options using a temporary user identity. Made-with: Cursor
a54c607 to
8b0b287
Compare
|
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA document, and I hereby sign the CLA |
|
bump |
|
can we get this in, @ascorbic ? (sorry for the tag) its real blocker right now 😓 |
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
|
|
||
| const isLoginRoute = url.pathname.startsWith("/_emdash/admin/login"); | ||
| const isPublicAdminRoute = | ||
| isLoginRoute || |
There was a problem hiding this comment.
As isLoginRoute is no longer used anywhere but here, the above line can be consolidated into here and reduce the number of variables.
| <div className="w-full max-w-md"> | ||
| {/* Header */} | ||
| <div className="text-center mb-8"> | ||
| <div className="text-4xl font-bold mb-2">— EmDash</div> |
There was a problem hiding this comment.
This is visually different from the Login page (see:
) and the Setup Wizard (see: )Could this structure be separated into a shared component?
There was a problem hiding this comment.
Included the LogoLockup component in the InviteAcceptPage
BenjaminPrice
left a comment
There was a problem hiding this comment.
Bugs
- From the PR Description:
(1) new URL("/api/auth/invite/accept", baseUrl) discarded the /_emdash path prefix because the leading / made it absolute
I'm unable to reproduce this locally. When I generate an invite locally it has the /_emdash path prefix.
What I liked
- Generally looks good. I was able to reproduce the new registration page after accepting an invite. A few other small comments have been added.
|
Sorry, one more thing. This new Invitation flow could really benefit from some E2E tests being added. |
…plify auth middleware route checks
|
I have read the CLA document, and I hereby sign the CLA |
|
I have read the CLA Document and I hereby sign the CLA |
…ng and API invite creation
There was a problem hiding this comment.
Bugs
- The unit test
createInviteToken > should create a token and return url + emailfails because the generated invite URL now uses/admin/invite/accept?token=instead of the expected/_emdash/api/auth/invite/accept?token=. Either the test assertion or the URL construction needs to be updated so they agree on the correct path.
BenjaminPrice
left a comment
There was a problem hiding this comment.
See comment about failing test
|
Need this in |
|
@SrikanthAlva it would be great if we could get this in. Are you able to get the tests passing? |
…test Fixes the two compounding bugs in the user invite system (Issue emdash-cms#67): - Bug 1: Invite URL drops /_emdash/ prefix. Fixed by pointing to admin UI page. - Bug 2: No UI to complete registration. Added InviteAcceptPage with passkey registration. - Bug 3 (from PR emdash-cms#81 review): Fixed failing test assertion to match new URL path. Based on PR emdash-cms#81 by @SrikanthAlva with the requested test fix applied. Closes emdash-cms#67
|
Superseded by #542 |
) * fix: repair invite flow — URL prefix + registration UI + fix failing test Fixes the two compounding bugs in the user invite system (Issue #67): - Bug 1: Invite URL drops /_emdash/ prefix. Fixed by pointing to admin UI page. - Bug 2: No UI to complete registration. Added InviteAcceptPage with passkey registration. - Bug 3 (from PR #81 review): Fixed failing test assertion to match new URL path. Based on PR #81 by @SrikanthAlva with the requested test fix applied. Closes #67 * fix: address review comments — remove unused code, use ULID, useSearch, fix duplicate button, simplify email store * fix(auth): remove signup from public admin routes Making /_emdash/admin/signup a public server-side route allowed unauthenticated direct access. The signup page is only intended to be reached via client-side navigation from the login page. Made-with: Cursor --------- Co-authored-by: Matt Kane <mkane@cloudflare.com>
Summary
Fixes the two compounding bugs in the user invite system that made it completely non-functional (Issue #67):
/_emdash/prefix:new URL("/api/auth/invite/accept", baseUrl)treats the leading/as an absolute path, discarding the/_emdashpath frombaseUrl. Fixed by using string concatenation and pointing the invite URL directly to the admin UI page.InviteAcceptPagein the admin SPA that validates the invite token, displays the user's email and assigned role, and drives passkey registration via the existing/auth/invite/completeendpoint.Files changed
packages/auth/src/invite.tspackages/core/tests/unit/auth/invite.test.ts/_emdash)packages/admin/src/components/InviteAcceptPage.tsxSignupPage.tsx)packages/admin/src/lib/api/users.tsvalidateInviteTokenandcompleteInviteSignupclient functionspackages/admin/src/lib/api/index.tspackages/admin/src/router.tsx/invite/acceptrouteTest plan
should preserve baseUrl path prefix in invite URLpassespnpm typecheckpasses (all packages)pnpm --silent lint:quickreturns 0 diagnosticspnpm formatclean/_emdash/admin/invite/acceptCloses #67
Made with Cursor