Conversation
The accept-invite page called better-auth's get-invitation before checking
for a session, but that endpoint requires one (401 without it). A first-time
invitee therefore always landed in the error state ('Invalid invitation')
and could never see the inline sign-up form — the exact users the page
exists for on invite-only self-hosted instances.
Reorder the effect: signed-out visitors go straight to the sign-in /
create-account choice, and account creation signs in with the email the
server returns from /api/system/invite-signup (derived from the invitation
token) instead of any client-side value. Signed-in users keep the full
get-invitation flow (org/role details, wrong-account detection).
Before: GET /api/auth/organization/get-invitation -> 401 -> error state.
After: logged-out user sees the create-account form; signup + signin +
accept complete without touching session-gated endpoints.
|
Confirming this on 0.6.9, self-hosted Compose install via Same split on the endpoint: The invitation row was Net effect on 0.6.9 is that nobody can join a self-hosted instance through the UI at all. Workaround for anyone else stuck here, driving the API directly on :4000 (the endpoints themselves are fine): Happy to test a build of this branch against my instance if that's useful. |
Summary
The
accept-invitepage could not complete its primary use case on self-hosted invite-only instances: a user opening an invitation link without already having an account.This PR fixes the invitation flow so signed-out invitees can reach the existing create-account flow, sign in automatically after account creation, and accept the invitation without the page falling back into an error state.
This complements #696, which made the route publicly accessible. After that change, visitors could reach the page, but the invitation flow still failed before signup.
Problem
Three issues combined to break the experience for first-time invitees:
Invitation details were requested before checking for a session.
organization.getInvitationrequires an authenticated session. Visiting/accept-invite/[id]while signed out immediately failed with401 Not authenticated, causing the page to render the "Invalid invitation" error instead of the signup UI. As a result, the existing!sessionsignup branch was effectively unreachable.Invitation loading failed on the current self-hosted better-auth setup.
On the tested
better-authv1.5.4 setup, the dashboard client issued aPOSTrequest fororganization/get-invitation, while the server exposed the route asGET. The invitation fetch therefore failed even for authenticated users, whileaccept-invitationandreject-invitationcontinued working because those routes arePOST.The page re-fetched the invitation after signup completed.
Creating an account automatically signs the user in, which changes the session and re-runs the page effect. That second fetch occurs after the invitation has already been accepted, replacing the success UI with the "Can't accept this invite" error state.
Evidence
API request log of one clean incognito run through signup on a self-hosted deployment of current
main:Both halves reproduced against the running stack:
Changes
File changed
apps/dashboard/src/app/accept-invite/[id]/page.tsxInvitation flow
/api/system/invite-signupcontinues to perform all server-side validation (pending status, expiration, inviter permissions, and email extraction).Invitation loading
GET /auth/organization/get-invitation?id=...endpoint via the app's existing api client, matching the server route used by the current self-hosted setup.POSTand were already working).State handling
Signup
/api/system/invite-signupinstead of any client-derived value.UI
Why this is safe
The client only changes when and how invitation metadata is requested.
Verification
Tested on a self-hosted Compose deployment built from this commit (API image untouched).
Before
/accept-invite/[id]in an incognito window immediately rendered "Can't accept this invite / Invalid invitation".…/api/proxy/api/auth/organization/get-invitation → 404.After
Regression checks
Build
docker build -f apps/dashboard/Dockerfile .succeeds (includes type checking).Checklist