Signup and Login Actions for a SaaS application

I am implementing signup and login for a SaaS application where every user is linked to an organization. Let’s say my application has the URL myapp.com, and every organization has a unique subdomain under my website e.g. myclient1.myapp.com

I have to derive organization ID from the unique subdomain myclient1 and assign it to organization_id field of user table in the database for every signup. For login also, I need to derive the organization_id and find the user by organization_id and the email.

How can I implement this correctly using AshAuthentication? I believe I need to use a custom strategy and make the database call there to fetch organization by unique subdomain and set the organization_id in changeset?

And how do I access the hostname in change method of the custom strategy? With Phoenix, I get this with Plug.Conn by using conn.host. But with Ash custom strategy, I inspected all the available variables - changeset, options and context, it doesn’t seem to be there.

1 Like

Generally this would be done by using multitenancy, and you’d set the tenant in a plug. For example,

In your user resource

multitenancy do
  strategy :attribute
  attribute :organization_id
  global? true # allows working with all orgs without setting a tenant
end

Then, in a plug ahead of the authentication logic, use set_tenant/2 from here Ash.PlugHelpers — ash v2.18.1 to set the tenant to the organization.id that you looked up from the plug.

AshAuthentication honors the tenant when interacting with your user resource. When a tenant is set while using the attribute strategy, the attribute is written to on changes and used in filters when accessing the data.

2 Likes

Thanks for the quick reply. I will give it a try.

A follow up question. Before the signup step, I am also verifying the email by sending a verification code to the email the verification code is stored in user_verifications table in the database.

The signup call happens after the user enters the password. At this stage, I need to make a DB call to check if the email is verified. What is the best way to check this? Do I need to implement a custom strategy/addon and make the DB call and throw an error if the email is not verified?

Here is what my signup flow looks like:

Are you using the built in confirmation tooling in ash_authentication? Regardless, the best way to handle this typically is to add a plug after authentication that checks if the user has been confirmed, and if not redirect to the “please verify your email or resend” page.

3 Likes

No, I was not using the built in confirmation tooling. I was looking at the docs for that here. It seems that confirmation tooling is used only for updates, but I’m creating a new record in the signup action. Is it possible to use confirmation tooling while creating a record?

@jimsynz can correct me if I’m wrong, but this will work for creation as well as updates. You can then add a plug to check if confirmed_at is not set, and if not, redirect to a page telling them to check their email.