[GH-ISSUE #4223] Invitation workflow #9869

Closed
opened 2026-04-13 05:39:12 -05:00 by GiteaMirror · 21 comments
Owner

Originally created by @maelp on GitHub (Aug 25, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/4223

Is this suited for github?

  • Yes, this is suited for github

I want to create an invitation worklow:

  • as an admin, I create a user with some permissions, etc
  • he receives an invitation / emailVerification email
  • when he clicks on that email, it prompts the user to use a given preferred method for credential (set password, use Google social provider, magic link, etc)

for now I don't know if this is possible, or if there's an example of that flow?

how do I generate a "we created a user account for you, click here to add your credentials and join" email with the proper workflow?

Describe the solution you'd like

A natural invitation workflow:

  • the admin creates a "credential-less" user with the proper permissions in the backend
  • the user receives an email (both to verify that the email works, and to allow him to setup his credentials)

it is "functionaly" equivalent to creating a user with a random password, sending him a verification email, and then asking him to click on "change my password", but it's done "all-in-one", and also lets the user choose a different auth method (eg Google Account, etc)

Describe alternatives you've considered

  • create a user
  • ask the user to click on "I forgot my password"

but this is not very intuitive for new users

Additional context

No response

Originally created by @maelp on GitHub (Aug 25, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/4223 ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. I want to create an invitation worklow: - as an admin, I create a user with some permissions, etc - he receives an invitation / emailVerification email - when he clicks on that email, it prompts the user to use a given preferred method for credential (set password, use Google social provider, magic link, etc) for now I don't know if this is possible, or if there's an example of that flow? how do I generate a "we created a user account for you, click here to add your credentials and join" email with the proper workflow? ### Describe the solution you'd like A natural invitation workflow: - the admin creates a "credential-less" user with the proper permissions in the backend - the user receives an email (both to verify that the email works, and to allow him to setup his credentials) it is "functionaly" equivalent to creating a user with a random password, sending him a verification email, and then asking him to click on "change my password", but it's done "all-in-one", and also lets the user choose a different auth method (eg Google Account, etc) ### Describe alternatives you've considered - create a user - ask the user to click on "I forgot my password" but this is not very intuitive for new users ### Additional context _No response_
GiteaMirror added the enhancementlocked labels 2026-04-13 05:39:12 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Aug 25, 2025):

Better Auth gives you the building blocks to create an invitation workflow like you described, but it doesn’t provide a single, out-of-the-box flow for “credential-less” user invites with multi-method onboarding. Here’s how you can put it together:

  • You can create users without credentials and send invitation emails using the organization/invitation logic (demo example). The invitation object supports roles, expiration, and tracks status.
  • For passwordless onboarding, use the magic link plugin. You can customize the sendMagicLink function to generate links for each invited user and send them in batch (details). Tokens are one-time use and expire, so users can securely join and set up credentials.
  • After accepting the invitation, you can redirect users to a page where they choose how to set up their credentials: set a password, use a social provider (Google, etc.), or authenticate via magic link. Social login currently uses a single signIn.social() method, but there are proposals for more explicit sign-up/sign-in separation (discussion).
  • You can track onboarding state (e.g., via user fields or organization invites) and prompt users to complete setup after OAuth sign-in or magic link verification.
  • There’s a feature proposal to let users set their password immediately after confirming their email, which would improve onboarding for admin-created users (discussion).
  • If you want to offer other delivery methods (Slack, WhatsApp, etc.), you can customize the invitation callback (discussion).

So, while you’ll need to compose these features with some custom logic, you can achieve the “invite, verify, choose credentials” workflow with Better Auth. Let me know if you want code samples or more details on any step!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3221024767 --> @dosubot[bot] commented on GitHub (Aug 25, 2025): <!-- Answer --> Better Auth gives you the building blocks to create an invitation workflow like you described, but it doesn’t provide a single, out-of-the-box flow for “credential-less” user invites with multi-method onboarding. Here’s how you can put it together: - You can create users without credentials and send invitation emails using the organization/invitation logic ([demo example](https://github.com/better-auth/better-auth/blob/8c23eb07396478a51b4dc7de669c010cdadc5479/demo/nextjs/app/accept-invitation/%5Bid%5D/page.tsx)). The invitation object supports roles, expiration, and tracks status. - For passwordless onboarding, use the magic link plugin. You can customize the `sendMagicLink` function to generate links for each invited user and send them in batch ([details](https://github.com/better-auth/better-auth/issues/4216)). Tokens are one-time use and expire, so users can securely join and set up credentials. - After accepting the invitation, you can redirect users to a page where they choose how to set up their credentials: set a password, use a social provider (Google, etc.), or authenticate via magic link. Social login currently uses a single signIn.social() method, but there are proposals for more explicit sign-up/sign-in separation ([discussion](https://github.com/better-auth/better-auth/issues/1023)). - You can track onboarding state (e.g., via user fields or organization invites) and prompt users to complete setup after OAuth sign-in or magic link verification. - There’s a feature proposal to let users set their password immediately after confirming their email, which would improve onboarding for admin-created users ([discussion](https://github.com/better-auth/better-auth/discussions/3376)). - If you want to offer other delivery methods (Slack, WhatsApp, etc.), you can customize the invitation callback ([discussion](https://github.com/better-auth/better-auth/issues/1680)). So, while you’ll need to compose these features with some custom logic, you can achieve the “invite, verify, choose credentials” workflow with Better Auth. Let me know if you want code samples or more details on any step! <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/0fd78677-1cfb-4070-a766-d85b662a70bb?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/0fd78677-1cfb-4070-a766-d85b662a70bb?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/0fd78677-1cfb-4070-a766-d85b662a70bb?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/0fd78677-1cfb-4070-a766-d85b662a70bb?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/0fd78677-1cfb-4070-a766-d85b662a70bb?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/0fd78677-1cfb-4070-a766-d85b662a70bb?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/0fd78677-1cfb-4070-a766-d85b662a70bb?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/4223)
Author
Owner

@yakupensarsayin commented on GitHub (Aug 25, 2025):

Hey @dosu , Are you sure you can invite and register a user to an organization? https://www.better-auth.com/docs/plugins/organization#accept-invitation says "Make sure to call the acceptInvitation function after the user is logged in." @maelp and I both want to create a user without credentials. I tested it myself, and if the user isn't already logged in, they can't join the organization!

<!-- gh-comment-id:3221575166 --> @yakupensarsayin commented on GitHub (Aug 25, 2025): Hey @dosu , Are you sure you can invite and register a user to an organization? https://www.better-auth.com/docs/plugins/organization#accept-invitation says "Make sure to call the acceptInvitation function **after the user is logged in**." @maelp and I both want to create a user without credentials. I tested it myself, and if the user isn't already logged in, they can't join the organization!
Author
Owner

@Kinfe123 commented on GitHub (Aug 26, 2025):

right now there is no way of choosing the auth method when doing an invites. we are doing credential by default.

<!-- gh-comment-id:3224538736 --> @Kinfe123 commented on GitHub (Aug 26, 2025): right now there is no way of choosing the auth method when doing an invites. we are doing credential by default.
Author
Owner

@maelp commented on GitHub (Aug 26, 2025):

@Kinfe123 would there be a way for me to create a plugin / special page where the user is redirected after I send them an invitation link, so they can create the credentials for their user account?

Basically I would have already created a User item in my backend, I would give them an expirable InvitationToken, and when they go to /auth/accept-invitation?token= it would show them a custom-made page to select their credentials (and override the defaults I chose randomly when creating their user object)?

how would that work, can you give me a pointer for this?

<!-- gh-comment-id:3224641131 --> @maelp commented on GitHub (Aug 26, 2025): @Kinfe123 would there be a way for me to create a plugin / special page where the user is redirected after I send them an invitation link, so they can create the credentials for their user account? Basically I would have already created a User item in my backend, I would give them an expirable InvitationToken, and when they go to /auth/accept-invitation?token=<InvitationToken> it would show them a custom-made page to select their credentials (and override the defaults I chose randomly when creating their user object)? how would that work, can you give me a pointer for this?
Author
Owner

@AchillesDH commented on GitHub (Aug 30, 2025):

@maelp - Would the Anonymous plug-in not be suitable in this case? Something like this; at the begin of the workflow, partition the user as anonymous and send them a link to a page where they can provide their own credentials. Once they have tried to Login/Register with new credentials it will then cause an onLinkAccount callback where you can add your own logic to move data from the anonymous account to the new account with proper credentials.

<!-- gh-comment-id:3239403450 --> @AchillesDH commented on GitHub (Aug 30, 2025): @maelp - Would the Anonymous plug-in not be suitable in this case? Something like this; at the begin of the workflow, partition the user as anonymous and send them a link to a page where they can provide their own credentials. Once they have tried to Login/Register with new credentials it will then cause an [onLinkAccount callback](https://www.better-auth.com/docs/plugins/anonymous#link-account) where you can add your own logic to move data from the anonymous account to the new account with proper credentials.
Author
Owner

@nickdichev commented on GitHub (Sep 2, 2025):

I'm working on a similar problem, i want to invite users to sign up to the app with a token embedded in a query parameter. Then, I basically need an after user create hook to assign permissions for the user based on the token.

For the email/password case this can be solved in a couple of ways, for example by attaching a header on the fetch options of the auth client on the signUp call. However, it is a little trickier for the oauth flow.

For the oauth flow, it would be great if we could hook into the state generated on the server side to embed custom data that we get on the callback. My workaround for now is going to be to embed the token in the oauth callback url, since that is what the library is shoving into the oauth callback state under the hood.

<!-- gh-comment-id:3246100066 --> @nickdichev commented on GitHub (Sep 2, 2025): I'm working on a similar problem, i want to invite users to sign up to the app with a token embedded in a query parameter. Then, I basically need an after user create hook to assign permissions for the user based on the token. For the email/password case this can be solved in a couple of ways, for example by attaching a header on the fetch options of the auth client on the signUp call. However, it is a little trickier for the oauth flow. For the oauth flow, it would be great if we could hook into the state generated on the server side to embed custom data that we get on the callback. My workaround for now is going to be to embed the token in the oauth callback url, since that is what the library is shoving into the oauth callback state under the hood.
Author
Owner

@gwoodbridge commented on GitHub (Sep 4, 2025):

I'm doing this by redirecting from my accept-invite page to the login page with the invitation id attached as a url parameter if they hit the accept-invite page without a session. I then check on my login page after sign in success if there is an invitation id url parameter, if so go back to the accept-invite page. It works the same for my sign up page.

So my flow is:

  1. Send invite to user which includes setting roles/permissions.
  2. User gets invite link in email which goes to my accept-invite page.
  3. On accept-invite page, check for session. If they have one, show accept invitation info.
  4. If no session, redirect to /login?invitationId=xxxxxxxxx.
  5. If the user navigates to the sign up route on the login page, it keeps the url parameters.
  6. After successful sign in or sign up, check for url parameters, if there is an invitationId, redirect to accept-invite. Otherwise redirect to my app.
<!-- gh-comment-id:3255024815 --> @gwoodbridge commented on GitHub (Sep 4, 2025): I'm doing this by redirecting from my accept-invite page to the login page with the invitation id attached as a url parameter if they hit the accept-invite page without a session. I then check on my login page after sign in success if there is an invitation id url parameter, if so go back to the accept-invite page. It works the same for my sign up page. So my flow is: 1. Send invite to user which includes setting roles/permissions. 2. User gets invite link in email which goes to my accept-invite page. 3. On accept-invite page, check for session. If they have one, show accept invitation info. 4. If no session, redirect to /login?invitationId=xxxxxxxxx. 5. If the user navigates to the sign up route on the login page, it keeps the url parameters. 6. After successful sign in or sign up, check for url parameters, if there is an invitationId, redirect to accept-invite. Otherwise redirect to my app.
Author
Owner

@matiasb7 commented on GitHub (Sep 24, 2025):

@gwoodbridge If the user on 5) navigates to sign up but they should verify the email after that. How can we preserve that invitation id param? Because the url for verifying the email is auto generated by Better auth

<!-- gh-comment-id:3326154541 --> @matiasb7 commented on GitHub (Sep 24, 2025): @gwoodbridge If the user on 5) navigates to sign up but they should verify the email after that. How can we preserve that invitation id param? Because the url for verifying the email is auto generated by Better auth
Author
Owner

@gwoodbridge commented on GitHub (Sep 24, 2025):

@matiasb7 I'm using the OTP plugin for email verification so the user never leaves the flow and loses the invitation ID. With the standard invite, if you are calling the sendVerificationEmail manually, you can include the invitation ID in the callback url. If you are relying on automatically sending emails, you could add a function to lookup the email being passed in the database for any invitations, get the id and include it in your email url if there is one.

<!-- gh-comment-id:3326195839 --> @gwoodbridge commented on GitHub (Sep 24, 2025): @matiasb7 I'm using the OTP plugin for email verification so the user never leaves the flow and loses the invitation ID. With the standard invite, if you are calling the sendVerificationEmail manually, you can include the invitation ID in the callback url. If you are relying on automatically sending emails, you could add a function to lookup the email being passed in the database for any invitations, get the id and include it in your email url if there is one.
Author
Owner

@tokyovigilante commented on GitHub (Nov 8, 2025):

Would second this, I've built an invitation flow as above, but can't find a nice way to auto-login after the user sets a password, ie a redirect to the login page is forced.

It would be nice to create a session for the user after they accept their invite and set a password, so they can head straight to the app or an authenticated on-boarding page, rather than having to log in with the same password.

<!-- gh-comment-id:3506504957 --> @tokyovigilante commented on GitHub (Nov 8, 2025): Would second this, I've built an invitation flow as above, but can't find a nice way to auto-login after the user sets a password, ie a redirect to the login page is forced. It would be nice to create a session for the user after they accept their invite and set a password, so they can head straight to the app or an authenticated on-boarding page, rather than having to log in with the same password.
Author
Owner

@brianwk commented on GitHub (Nov 9, 2025):

Would second this, I've built an invitation flow as above, but can't find a nice way to auto-login after the user sets a password, ie a redirect to the login page is forced.

It would be nice to create a session for the user after they accept their invite and set a password, so they can head straight to the app or an authenticated on-boarding page, rather than having to log in with the same password.

Can't you force the session with hooks or something? For example this is how I set activeOrganizationId:

databaseHooks: {
      session: {
        create: {
          before: async (session) => {
            if (session.activeOrganizationId) {
              return { data: session };
            } else {
              const { userId } = session;
              const user = await authComponent.getAnyUserById(ctx, userId);
              return {
                data: {
                  ...session,
                  activeOrganizationId: user!.organizationId,
                },
              };
            }
          },
        },
      },
    },

The session object has user which will determine if you are logged in I think? Just not sure how to put it all together but I'm working on something similar and I will post a gist in here once I sort something out... Only thing is this project uses convex-better-auth adapter so unsure if the code will have to modified for your setup.

But basically I am thinking maybe I can use the anonymous user plugin and that will create the session. And then somehow you can change the session to the actual user, or use the database directly to modify the user from anonymous to non-anonymous?


So I was able to create an anonymous user during the invite process if the e-mail isn't found. After I created the anonymous user I used the database adapter to update the e-mail of the anonymous user to the invitee e-mail. Then I use a middleware on for example /organization/get-invite:

    hooks: {
      before: createAuthMiddleware(async (ctx) => {
        if (ctx.path === "/organization/get-invitation") {
          const invitation = await getUnauthedInvitation(
            ctx.context,
            ctx.query?.id
          );
          if (ctx.context.session?.session.userId === undefined) {
            const user = await ctx.context.adapter.findOne<UserWithAnonymous>({
              model: "user",
              where: [
                {
                  field: "isAnonymous",
                  operator: "eq",
                  value: true,
                },
                { field: "id", operator: "eq", value: invitation.inviteeId! },
              ],
            });
            if (user?.isAnonymous) {
              // Force the session to login as this anonymous user
              const session = (await ctx.context.adapter.findOne<Session>({
                model: "session",
                where: [
                  {
                    field: "userId",
                    operator: "eq",
                    value: user.id,
                  },
                ],
              }))!;
              ctx.context.session = { session, user };
            }
          }
        }

And here is getUnauthedInvitation:

export const getUnauthedInvitation = async (
  authCtx: AuthContext,
  id: string
) => {
  const invitation: (Invitation & AuthDoc<"invitation">) | null =
    await authCtx.adapter.findOne({
      model: "invitation",
      where: [
        {
          field: "id",
          operator: "eq",
          value: id,
        },
      ],
    });
  // The invitation does not exist
  if (
    !invitation ||
    invitation.status !== "pending" ||
    !invitation.expiresAt ||
    invitation.expiresAt < new Date()
  ) {
    throw new APIError("NOT_FOUND", {
      message: "Invitation not found or expired.",
    });
  }
  const invitee: AuthDoc<"user"> | null = await authCtx.adapter.findOne({
    model: "user",
    where: [
      {
        field: "id",
        operator: "eq",
        value: invitation.inviteeId!,
      },
    ],
  });
  if (!invitee) {
    throw new APIError("NOT_FOUND", {
      message: "Invitee user not found.",
    });
  }
  if (invitee.isAnonymous && invitee._id === invitation.id) {
    // Create auth session
    authCtx.setNewSession({
      user: invitee,
      session: {
        token: invitation.id,
        id: invitation.id,
        userId: invitee._id,
        createdAt: new Date(),
        updatedAt: new Date(),
        expiresAt: invitation.expiresAt,
      },
    });
  }

  return invitation;
};

I also added some additional fields to the organization invitation table. The middleware basically tricks betterAuth into thinking that you are logged in as the anonymous user. I change the anonymous user e-mail also using the database adapter when the invite is created. Now I have to repeat this and make it work for the signup endpoint. I am unsure if it will work or if I will have to make a custom signup endpoint for invitations, since I'm unsure if I can add an arbitrary query string to the betterAuth api signup call.

Also with Convex adapter I was unable to get user, etc with the prewritten methods and had to use the database adapter in the context of the middleware. But I think this may be an issue with the fact that in my middleware I am using ctx as an argument and the variable to access these things is also ctx.

In any case, if I get it more cleaned up I will publish it as a gist.


It is possible to pass arbitrary query string to the sign-up/email API. I did this by adding fetchOptions: { query: { invitationId } } to the object arguments. Then in your middleware you can get this query string as follows:

    hooks: {
      before: createAuthMiddleware(async (ctx) => {
        if (ctx.path === "/sign-up/email") {
          const { invitationId } = ctx.query!;
          await guestInvite(ctx, invitationId as string);
        }

I don't know that setting the session to the anonymous user like this will actually work. This is because I've changed the e-mail of the anonymous user to match the invitation so BetterAuth doesn't throw a "recipient doesn't match" error. But I was hoping that I could just make this anonymous user not anonymous anymore and BetterAuth would just update the user fields in the "linking" process since I have deleting the user disabled. -- As I suspected the signup is blocked since the e-mail is already registered. But this got me thinking.... do I actually need an anonymous user at all? Or is just sending the session good enough to bypass the default BetterAuth behavior?


Update: You don't even need to use an anonymous user. You can just create an "anonymous session" -- you will want to ensure that the e-mail of the invite is not registered. If the e-mail of the invite is registered, you should fail I think. Basically I created a bogus session like this -- it only creates the bogus session if the user is not currently logged in:

  const invitation = await getUnauthedInvitation(ctx.context, invitationId);
  ctx.context.session = {
    session: {
      id: "anonymous",
      token: "anonymous-token",
      userId: "anonymous",
      createdAt: new Date(),
      updatedAt: new Date(),
      expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
    },
    user: {
      id: "anonymous",
      email: invitation.email,
      emailVerified: true,
      name: "anonymous",
      createdAt: new Date(),
      updatedAt: new Date(),
    },
  };

Also, if this is too insane please tell me a better way to do it.

<!-- gh-comment-id:3508759628 --> @brianwk commented on GitHub (Nov 9, 2025): > Would second this, I've built an invitation flow as above, but can't find a nice way to auto-login after the user sets a password, ie a redirect to the login page is forced. > > It would be nice to create a session for the user after they accept their invite and set a password, so they can head straight to the app or an authenticated on-boarding page, rather than having to log in with the same password. Can't you force the session with hooks or something? For example this is how I set activeOrganizationId: ```ts databaseHooks: { session: { create: { before: async (session) => { if (session.activeOrganizationId) { return { data: session }; } else { const { userId } = session; const user = await authComponent.getAnyUserById(ctx, userId); return { data: { ...session, activeOrganizationId: user!.organizationId, }, }; } }, }, }, }, ``` The session object has user which will determine if you are logged in I think? Just not sure how to put it all together but I'm working on something similar and I will post a gist in here once I sort something out... Only thing is this project uses convex-better-auth adapter so unsure if the code will have to modified for your setup. But basically I am thinking maybe I can use the anonymous user plugin and that will create the session. And then somehow you can change the session to the actual user, or use the database directly to modify the user from anonymous to non-anonymous? ----- So I was able to create an anonymous user during the invite process if the e-mail isn't found. After I created the anonymous user I used the database adapter to update the e-mail of the anonymous user to the invitee e-mail. Then I use a middleware on for example /organization/get-invite: ```ts hooks: { before: createAuthMiddleware(async (ctx) => { if (ctx.path === "/organization/get-invitation") { const invitation = await getUnauthedInvitation( ctx.context, ctx.query?.id ); if (ctx.context.session?.session.userId === undefined) { const user = await ctx.context.adapter.findOne<UserWithAnonymous>({ model: "user", where: [ { field: "isAnonymous", operator: "eq", value: true, }, { field: "id", operator: "eq", value: invitation.inviteeId! }, ], }); if (user?.isAnonymous) { // Force the session to login as this anonymous user const session = (await ctx.context.adapter.findOne<Session>({ model: "session", where: [ { field: "userId", operator: "eq", value: user.id, }, ], }))!; ctx.context.session = { session, user }; } } } ``` And here is getUnauthedInvitation: ```ts export const getUnauthedInvitation = async ( authCtx: AuthContext, id: string ) => { const invitation: (Invitation & AuthDoc<"invitation">) | null = await authCtx.adapter.findOne({ model: "invitation", where: [ { field: "id", operator: "eq", value: id, }, ], }); // The invitation does not exist if ( !invitation || invitation.status !== "pending" || !invitation.expiresAt || invitation.expiresAt < new Date() ) { throw new APIError("NOT_FOUND", { message: "Invitation not found or expired.", }); } const invitee: AuthDoc<"user"> | null = await authCtx.adapter.findOne({ model: "user", where: [ { field: "id", operator: "eq", value: invitation.inviteeId!, }, ], }); if (!invitee) { throw new APIError("NOT_FOUND", { message: "Invitee user not found.", }); } if (invitee.isAnonymous && invitee._id === invitation.id) { // Create auth session authCtx.setNewSession({ user: invitee, session: { token: invitation.id, id: invitation.id, userId: invitee._id, createdAt: new Date(), updatedAt: new Date(), expiresAt: invitation.expiresAt, }, }); } return invitation; }; ``` I also added some additional fields to the organization invitation table. The middleware basically tricks betterAuth into thinking that you are logged in as the anonymous user. I change the anonymous user e-mail also using the database adapter when the invite is created. Now I have to repeat this and make it work for the signup endpoint. I am unsure if it will work or if I will have to make a custom signup endpoint for invitations, since I'm unsure if I can add an arbitrary query string to the betterAuth api signup call. Also with Convex adapter I was unable to get user, etc with the prewritten methods and had to use the database adapter in the context of the middleware. But I think this may be an issue with the fact that in my middleware I am using ctx as an argument and the variable to access these things is also ctx. In any case, if I get it more cleaned up I will publish it as a gist. ----- It is possible to pass arbitrary query string to the sign-up/email API. I did this by adding fetchOptions: { query: { invitationId } } to the object arguments. Then in your middleware you can get this query string as follows: ```ts hooks: { before: createAuthMiddleware(async (ctx) => { if (ctx.path === "/sign-up/email") { const { invitationId } = ctx.query!; await guestInvite(ctx, invitationId as string); } ``` I don't know that setting the session to the anonymous user like this will actually work. This is because I've changed the e-mail of the anonymous user to match the invitation so BetterAuth doesn't throw a "recipient doesn't match" error. But I was hoping that I could just make this anonymous user not anonymous anymore and BetterAuth would just update the user fields in the "linking" process since I have deleting the user disabled. -- As I suspected the signup is blocked since the e-mail is already registered. But this got me thinking.... do I actually need an anonymous user at all? Or is just sending the session good enough to bypass the default BetterAuth behavior? --- Update: You don't even need to use an anonymous user. You can just create an "anonymous session" -- you will want to ensure that the e-mail of the invite is not registered. If the e-mail of the invite is registered, you should fail I think. Basically I created a bogus session like this -- it only creates the bogus session if the user is not currently logged in: ```ts const invitation = await getUnauthedInvitation(ctx.context, invitationId); ctx.context.session = { session: { id: "anonymous", token: "anonymous-token", userId: "anonymous", createdAt: new Date(), updatedAt: new Date(), expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), }, user: { id: "anonymous", email: invitation.email, emailVerified: true, name: "anonymous", createdAt: new Date(), updatedAt: new Date(), }, }; ``` Also, if this is too insane please tell me a better way to do it.
Author
Owner

@Fefedu973 commented on GitHub (Nov 9, 2025):

I had the same issue and managed to get smth to work but it would be great to have a built in way to do this properly

<!-- gh-comment-id:3508863320 --> @Fefedu973 commented on GitHub (Nov 9, 2025): I had the same issue and managed to get smth to work but it would be great to have a built in way to do this properly
Author
Owner

@tokyovigilante commented on GitHub (Nov 10, 2025):

Can't you force the session with hooks or something?

I ended up just calling the normal login endpoint programatically, given the user has just provided the password in plain text into the client to register we have it in memory so may as well use it.

<!-- gh-comment-id:3509043869 --> @tokyovigilante commented on GitHub (Nov 10, 2025): > Can't you force the session with hooks or something? I ended up just calling the normal login endpoint programatically, given the user has just provided the password in plain text into the client to register we have it in memory so may as well use it.
Author
Owner

@brianwk commented on GitHub (Nov 10, 2025):

Can't you force the session with hooks or something?

I ended up just calling the normal login endpoint programatically, given the user has just provided the password in plain text into the client to register we have it in memory so may as well use it.

Oh I was thinking of another problem.... the fact that you can't view the invitation without logging in. That's a good idea for logging in after signup though. Otherwise you would probably have to manually create the session and push out the cookies?

<!-- gh-comment-id:3509533214 --> @brianwk commented on GitHub (Nov 10, 2025): > > Can't you force the session with hooks or something? > > I ended up just calling the normal login endpoint programatically, given the user has just provided the password in plain text into the client to register we have it in memory so may as well use it. Oh I was thinking of another problem.... the fact that you can't view the invitation without logging in. That's a good idea for logging in after signup though. Otherwise you would probably have to manually create the session and push out the cookies?
Author
Owner

@tokyovigilante commented on GitHub (Nov 10, 2025):

Oh I was thinking of another problem.... the fact that you can't view the invitation without logging in.

Oh right. I assumed that endpoint would have to be unauthenticated?

<!-- gh-comment-id:3510147407 --> @tokyovigilante commented on GitHub (Nov 10, 2025): > Oh I was thinking of another problem.... the fact that you can't view the invitation without logging in. Oh right. I assumed that endpoint would have to be unauthenticated?
Author
Owner

@dosubot[bot] commented on GitHub (Feb 9, 2026):

Hi, @maelp. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary

  • You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods.
  • The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow.
  • Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling.
  • Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages.
  • The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding.

Next Steps

  • Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open.
  • Otherwise, this issue will be automatically closed in 7 days.

Thanks for your understanding and contribution!

<!-- gh-comment-id:3872684771 --> @dosubot[bot] commented on GitHub (Feb 9, 2026): Hi, @maelp. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary** - You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods. - The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow. - Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling. - Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages. - The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding. **Next Steps** - Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open. - Otherwise, this issue will be automatically closed in 7 days. Thanks for your understanding and contribution!
Author
Owner

@dosubot[bot] commented on GitHub (Feb 9, 2026):

Hi, @maelp. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary

  • You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods.
  • The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow.
  • Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling.
  • Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages.
  • The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding.

Next Steps

  • Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open.
  • Otherwise, this issue will be automatically closed in 7 days.

Thanks for your understanding and contribution!

<!-- gh-comment-id:3872685049 --> @dosubot[bot] commented on GitHub (Feb 9, 2026): Hi, @maelp. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary** - You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods. - The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow. - Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling. - Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages. - The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding. **Next Steps** - Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open. - Otherwise, this issue will be automatically closed in 7 days. Thanks for your understanding and contribution!
Author
Owner

@dosubot[bot] commented on GitHub (Feb 9, 2026):

Hi, @maelp. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary

  • You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods.
  • The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow.
  • Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling.
  • Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages.
  • The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding.

Next Steps

  • Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open.
  • Otherwise, this issue will be automatically closed in 7 days.

Thanks for your understanding and contribution!

<!-- gh-comment-id:3872685430 --> @dosubot[bot] commented on GitHub (Feb 9, 2026): Hi, @maelp. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary** - You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods. - The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow. - Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling. - Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages. - The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding. **Next Steps** - Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open. - Otherwise, this issue will be automatically closed in 7 days. Thanks for your understanding and contribution!
Author
Owner

@dosubot[bot] commented on GitHub (Feb 9, 2026):

Hi, @maelp. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary

  • You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods.
  • The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow.
  • Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling.
  • Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages.
  • The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding.

Next Steps

  • Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open.
  • Otherwise, this issue will be automatically closed in 7 days.

Thanks for your understanding and contribution!

<!-- gh-comment-id:3872685994 --> @dosubot[bot] commented on GitHub (Feb 9, 2026): Hi, @maelp. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary** - You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods. - The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow. - Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling. - Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages. - The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding. **Next Steps** - Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open. - Otherwise, this issue will be automatically closed in 7 days. Thanks for your understanding and contribution!
Author
Owner

@dosubot[bot] commented on GitHub (Feb 9, 2026):

Hi, @maelp. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary

  • You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods.
  • The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow.
  • Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling.
  • Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages.
  • The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding.

Next Steps

  • Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open.
  • Otherwise, this issue will be automatically closed in 7 days.

Thanks for your understanding and contribution!

<!-- gh-comment-id:3872687175 --> @dosubot[bot] commented on GitHub (Feb 9, 2026): Hi, @maelp. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary** - You requested an invitation workflow for admins to create users without credentials and send email invites for users to verify and set up sign-in methods. - The team clarified that Better Auth offers building blocks but no out-of-the-box multi-method invite flow. - Community members shared various workarounds involving invitations, magic link plugin, custom onboarding pages, redirects, and session handling. - Discussions included auto-login after password setup using hooks or programmatic login and questions about custom credential setup pages. - The feature currently requires composing existing tools with custom logic, with ongoing community proposals to improve onboarding. **Next Steps** - Please let me know if this issue is still relevant to the latest version of better-auth by commenting here to keep the discussion open. - Otherwise, this issue will be automatically closed in 7 days. Thanks for your understanding and contribution!
Author
Owner

@ping-maxwell commented on GitHub (Feb 11, 2026):

Hello all, we're moving all feature requests or enhancement issues over to Github Discussions.

I've went ahead and created the discussion here:

https://github.com/better-auth/better-auth/discussions/7913

<!-- gh-comment-id:3883021117 --> @ping-maxwell commented on GitHub (Feb 11, 2026): Hello all, we're moving all feature requests or enhancement issues over to Github Discussions. I've went ahead and created the discussion here: https://github.com/better-auth/better-auth/discussions/7913
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9869