[GH-ISSUE #6716] Organization Plugin: Allow unverified users / not logged in users to accept invitations #10599

Open
opened 2026-04-13 06:50:37 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @joshsedl on GitHub (Dec 12, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6716

Originally assigned to: @ping-maxwell on GitHub.

Is this suited for github?

  • Yes, this is suited for github

I have the following organization invite workflow for unregistered users right now:

  • A user without an account is being invited to an organization
  • He gets sent an email, to the registration form, with the invitationId as a query parameter
  • Once he registers, I create the user using authClient.signUp.email()
  • After the signup is complete, I would like to accept the invitation, BUT:
    1. The user only has signed up and is NOT logged in yet, so I don't have a user session, meaning I get an "UNAUTHORIZED" API Error
    2. I have emailVerification.sendOnSignUp set to TRUE, so I can't simply auto sign-in.

As a current workaround, I drag the invitationId up to the verification Mail, and verify it through our middleware, if set (since there is no "onAfterVerification" hook, but that's another story)

Describe the solution you'd like

Provide an option to invite a user by email / id and make sure users with emailVerified set to false can also accept invitations.

Describe alternatives you've considered

See solution.

Additional context

No response

Originally created by @joshsedl on GitHub (Dec 12, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6716 Originally assigned to: @ping-maxwell on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. I have the following organization invite workflow for unregistered users right now: - A user without an account is being invited to an organization - He gets sent an email, to the registration form, with the invitationId as a query parameter - Once he registers, I create the user using `authClient.signUp.email()` - After the signup is complete, I would like to accept the invitation, BUT: 1. The user only has signed up and is NOT logged in yet, so I don't have a user session, meaning I get an "UNAUTHORIZED" API Error 2. I have emailVerification.sendOnSignUp set to TRUE, so I can't simply auto sign-in. As a current workaround, I drag the invitationId up to the verification Mail, and verify it through our middleware, if set (since there is no "onAfterVerification" hook, but that's another story) ### Describe the solution you'd like Provide an option to invite a user by email / id and make sure users with `emailVerified` set to false can also accept invitations. ### Describe alternatives you've considered See solution. ### Additional context _No response_
GiteaMirror added the credentialsenhancementorganization labels 2026-04-13 06:50:37 -05:00
Author
Owner

@Ridhim-RR commented on GitHub (Dec 14, 2025):

looking into this

<!-- gh-comment-id:3650465284 --> @Ridhim-RR commented on GitHub (Dec 14, 2025): looking into this
Author
Owner

@Ridhim-RR commented on GitHub (Dec 15, 2025):

@himself65 what you think of this as I have raised a pr but it was not right so i have closed it .

<!-- gh-comment-id:3653475467 --> @Ridhim-RR commented on GitHub (Dec 15, 2025): @himself65 what you think of this as I have raised a pr but it was not right so i have closed it .
Author
Owner

@carry0987 commented on GitHub (Mar 7, 2026):

@Ridhim-RR @joshsedl
I've been facing the same issue — invited users who haven't registered yet are forced through the full email verification flow, which adds unnecessary friction since clicking the invitation link already proves email ownership.

As a workaround, I'm using databaseHooks.user.create.before to check if the signing-up user's email has a pending invitation. If so, I set emailVerified: true automatically, which skips the verification email and allows the session to be created immediately. The user can then proceed to accept the invitation right away.

databaseHooks: {
  user: {
    create: {
      before: async (user) => {
        const pendingInvitation = await db.query.invitations.findFirst({
          where: and(
            eq(schema.invitations.email, user.email),
            eq(schema.invitations.status, "pending"),
          ),
        });
        if (pendingInvitation) {
          return { data: { ...user, emailVerified: true } };
        }
        return { data: user };
      },
    },
  },
},

Security-wise this seems reasonable: the invitation email itself serves as proof of ownership, and acceptInvitation still validates that the logged-in user's email matches the invitation (case-insensitive). Even if someone registers with an invited email without access to the inbox, they'd still need the invitationId to actually join the organization.

That said, it would be great to have native support for this — perhaps an option like skipEmailVerificationForInvitedUsers: true on the organization plugin, so I don't have to rely on hooks for such a common flow.

<!-- gh-comment-id:4016877817 --> @carry0987 commented on GitHub (Mar 7, 2026): @Ridhim-RR @joshsedl I've been facing the same issue — invited users who haven't registered yet are forced through the full email verification flow, which adds unnecessary friction since clicking the invitation link already proves email ownership. As a workaround, I'm using `databaseHooks.user.create.before` to check if the signing-up user's email has a pending invitation. If so, I set `emailVerified: true` automatically, which skips the verification email and allows the session to be created immediately. The user can then proceed to accept the invitation right away. ```ts databaseHooks: { user: { create: { before: async (user) => { const pendingInvitation = await db.query.invitations.findFirst({ where: and( eq(schema.invitations.email, user.email), eq(schema.invitations.status, "pending"), ), }); if (pendingInvitation) { return { data: { ...user, emailVerified: true } }; } return { data: user }; }, }, }, }, ``` Security-wise this seems reasonable: the invitation email itself serves as proof of ownership, and `acceptInvitation` still validates that the logged-in user's email matches the invitation (case-insensitive). Even if someone registers with an invited email without access to the inbox, they'd still need the `invitationId` to actually join the organization. That said, it would be great to have native support for this — perhaps an option like `skipEmailVerificationForInvitedUsers: true` on the organization plugin, so I don't have to rely on hooks for such a common flow.
Author
Owner

@ping-maxwell commented on GitHub (Apr 9, 2026):

yeah this should probably be built into the plugin

<!-- gh-comment-id:4217060052 --> @ping-maxwell commented on GitHub (Apr 9, 2026): yeah this should probably be built into the plugin
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10599