Skip to content

organizations.invitations.listMine() (GET /organization/list-user-invitations) answers 403 EMAIL_VERIFICATION_REQUIRED_FOR_INVITATION for every unverified user, although plugin-auth sets requireEmailVerificationOnInvitation: false for exactly that deployment shape #16569

Description

@claude

Found while driving the organizations.* routes for #14314 (card 3 of the #12104 family). Out of that card's ruled scope (listMine is already typed and the defect is a runtime refusal), so recorded here. No assignee, no label — left for triage.

What plugin-auth declares

packages/plugins/plugin-auth/src/auth-manager.ts, the organization({ ... }) options:

Without a mailer wired in framework, requiring email verification before accepting invitations dead-ends every invite flow with FORBIDDEN EMAIL_VERIFICATION_REQUIRED…. Default-off here keeps the built-in /accept-invitation route usable for pilots

so requireEmailVerificationOnInvitation: false is set, and the SDK's organizations.invitations.listMine JSDoc says it is "Used by the per-user Invitations inbox page."

What the vendor does

better-auth 1.7.2, plugins/organization/routes/crud-invites.mjs, listUserInvitations: if (session && !session.user.emailVerified) throw APIError.from('FORBIDDEN', EMAIL_VERIFICATION_REQUIRED_FOR_INVITATION) — unconditional, it does not read requireEmailVerificationOnInvitation (the accept / reject / get-invitation routes DO read it, via shouldRequireVerifiedEmailForInvitationIdAction).

Measured

Real AuthManager (better-auth 1.7.2, organization plugin) over a real SqlDriver (better-sqlite3), no mailer:

  1. owner signs up, creates an organization, invites b@example.com
  2. b@example.com signs up through the invitation carve-out (email stays unverified — there is no mailer to verify it)
  3. GET /organization/list-user-invitations as B -> 403 {"message":"Email verification required to view or list invitations for the session email","code":"EMAIL_VERIFICATION_REQUIRED_FOR_INVITATION"}
  4. POST /organization/accept-invitation as B with the same invitation id -> 200 (the option is honoured here)

The same 403 came back through the real ObjectStackClient (client.organizations.invitations.listMine() rejected with that message). So on the deployment shape the option exists for, the invitee can ACCEPT an invitation whose id they were handed but can never LIST it — the inbox page the SDK method serves is empty-by-403 for every user until a mailer verifies them.

Class

Reproducible defect on a declared capability (the inbox is advertised for pilots without a mailer; the route refuses them). Fix shape is a triage question: an ObjectStack before-hook on /organization/list-user-invitations that answers the listing itself when requireEmailVerificationOnInvitation is false, an upstream report to better-auth, or documenting the inbox as verified-users-only.

Refs: #14314 (where it was measured), #12104 (family head).


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions