Best way to handle user invites for multi-app?
Wondering if I could get some guidance. My use case, I have an admin app(Next) and an employee app(Expo). What I am wanting to do is allow my admin users to invite other users who can be either have an admin role, or an employee role. Where I am getting stuck is the routing for this. the admin app might be on a.domain.com and the employee app on b.domain.com, with my kinde domain using auth.domain.com.
Any guidance would be wonderful. Thank you!
9 Replies
my initial thought was to just add a role check in the middleware on the admin app, and redirect to a download page if they have an employee role.
Hi bolg55,
Thanks for the question!
Your approach of checking roles in middleware is totally valid. To restate the overall flow:
1. Register two different apps in Kinde (one for your Next.js admin app, one for your Expo employee app).
2. When inviting users, create them and assign roles using the Kinde Management API.
I assume you’ll also be sending an email to let the users know. For this, you can make use of the
user.created
webhook.
- One option is to have the email link always point to your Next.js app, and then use middleware to check the user’s role and redirect them to the correct destination.
- Another option, if you’re using the webhook, is to look at the payload:
The payload includes a source
field api
when the user is created by an API. You can combine that with a Management API call to check the user’s role and decide which link to send them directly—removing the need for middleware routing.
Ultimately, there isn’t a strict right or wrong approach here. You can pick whichever method fits best with your setup.
Let me know what else I can help you with!Oh nice, the webhook option might be a nice solution then. And yes, I intend to send an email, so if I need to use the webhook for that anyways then that might be a good fit.
Great!
Please let me know how that goes and if you need any help there.
Please let me know how that goes and if you need any help there.
With this solution- is there a way that the admin can see a pending invite/revoke/resend? Similar to how it would be done in say, better-auth? I suppose not since it is creating the user in the invite sequence, right?
Hi bolg55,
Great follow-up question. At the moment, Kinde doesn’t have a native “pending invites” object like you might see in BetterAuth or similar systems. When you create a user via the Management API as part of your invite sequence, that user record is created immediately in Kinde, so from Kinde’s perspective, they already exist (not in a “pending” state).
What you can do is build this on your side:
- Use the
user.created
webhook to capture when an invite is triggered.
- Store your own metadata (e.g., “invited but not yet onboarded”) in your database.
- Once the user logs in and completes onboarding, you can flip that status to “active.”
- This also gives you a place to handle resend (by sending another email with the login link) or revoke (by deleting the user in Kinde if needed).
So short answer: you’re right - since the user gets created up front, there isn’t a built-in pending state. But you can layer a simple tracking system on top to get that same functionality.Kinde docs
Send user invitations with webhooks
Describes several methods for sending invitations to end users, including from one organization member to another.
Thanks- I am really struggling with the callback. I want the user to be able to click the button in the email, and either have it sign them in automatically, or at the very least take them to the sign in page. But I can’t see a way to do that. I keep getting errors about the state, and if I randomly generate a state and append it to the url, it fails when they enter the OTP sent after log in
Hi bolg55,
I don’t think I have the whole picture yet, so let me share my assumption: you have an Admin app (Next.js), an Employee app (Expo), and you want Admins to invite users who then sign in to the right app with the right role.
One of the reasons you’re seeing the state error could be that the login flow isn’t starting on your app. The Kinde SDK needs to generate and store
state
+ PKCE when the flow begins, and if the user goes straight to a Kinde URL or if the start and callback land on different domains, you’ll get a mismatch.
What to do instead:
- In your email, send the user to your app’s login start route (not directly to Kinde):
- Admin: https://a.domain.com/api/auth/login?org_code=...
- Employee: a universal link or custom scheme (e.g. myapp://invite?org_code=...
or https://b.domain.com/open?...
) that calls the SDK’s login()
in the Expo app.
- Make sure the callback URL exactly matches what you’ve configured in Kinde for that specific application.
- Don’t try to generate your own state
value—the SDK handles that.
It’s possible I’m missing part of your setup. Could you describe a bit more about:
- The exact links you’re putting in the invite email,
- The callback URLs you’ve registered in Kinde for both apps, and
That will help me give you more precise guidance.Ok, thanks- I thought I had tried it using the https://a.domain.com/api/auth/login?org_code=... way but I’ll need to check again.
I think I was skipping using a web hook for testing and just passing in the values and firing an email via resend.
But yes, you’ve got the flow I am looking for down.
I’ll play around some more and let you know if I run into any issues. The setting of state was a last resort I had attempted because I kept getting an error. I’ll revisit. Thank you again for your guidance