This isn't out of the box, but is relatively easy to implement.
- After each user is added successfully, create a list of codes in their
user.data.inviteCodes
field (which can be an array). It's a good idea to have the codes be alphanumeric because FusionAuth's elastic search indexing handles those types of values best. Let's call this user the inviter user. Make sure each code is unique across all users.
- When a user tries to register with a code, let's call that user the invitee user.
- Build a page in your application to display the list of
user.data.inviteCodes
to prospective inviters.
- Create a custom registration form and have one of the fields be an invite code, to be provided by the invitee user (because they got it from the inviter user).
- You could prepopulate this via a link by customizing the theme and having javascript pull the value from a query parameter and put it into the form.
- Create a self-service registration validation lambda.
- In that lambda, search for the code.
- If it is not found, add an error. This error will prevent the user from registering.
- If it is found, take the following steps:
- Allow the registration to succeed.
- Add a webhook to listen for the create user event, which reads the invitation code.
- From the webhook, update the inviter user to remove the used code from the
user.data.inviteCodes
, which means that code can't be used by future invitees.
- That same webhook can update the invitee's
user.data.inviteCodes
field so that they can now become inviters (or maybe that happens later, depending on business logic).
If invitees use the same code within time period the elasticsearch index is updated (usually 1 second), there may be a race condition that would allow two invitees to register with the same code.
If absolute isolation in the invite code processing is important, use Lambda HTTP connect in the self-service registration validation lambda to check if a code is valid, and have that read from an RDBMS.
In this case, you'll need to provide the code and the inviter email address in the form so the lambda can provide it to the API. These fields can both be hidden.
You can also consider adding an expiry timestamp to the user.data.inviteCodes
if that functionality is needed.
Here's an example of the user.data.inviteCodes
value:
"inviteCodes" : [
{
"invcode": "abc123",
"exp": 1712679467
},
{
"invcode": "234jklasdf",
"exp": 183678467
}
]
And here's an example of a queryString that will pull the user with the abc123
invite code, or return zero records if that is not found.
data.inviteCodes.invcode:abc123
Read more about elasticsearch arrays.