Better Auth Organizations – The Basics (Part 1)
By OrcDev
Summary
Topics Covered
- Drizzle Beats Better Auth Migrations
- Server Actions Trump Client APIs
- Custom Switcher Enables Org Context
- Database Hook Sets Default Org
Full Transcript
In this video, we are going to implement better o organizations. We're going to create this organization switcher where we can choose our current active
organization and also we are going to create this form where we can create a new organization. We are going to cover
new organization. We are going to cover all the basics for better o organizations. We are still not going to
organizations. We are still not going to work on things like invitations, roles or adding new members. That's why this video is called part one. Let's start.
We have here our better oath starter.
You have the GitHub repository in the description below if you need it. And we
are going to implement now organizations by better o. So we are going to docs.
Then here we are going to plugins and we are clicking on organization.
So here we have the start that we need for organizations and first thing we need to do is to add the organization
plugin inside of our o.ts file. So I'm
opening the code and here we are going to o.ts and we have our plugins right here. We
have next cookies because we need that one for next.js JS and we are going to add the organization plugin right here
and we are going to import it from here better off/plugins.
So I'm adding that one to our imports and that one is done. So now we can migrate our database because we are adding now organizations members and
bunch of new tables. We need to run new migrations. So this one is not going to
migrations. So this one is not going to work for our NexJS project because we are using Drizzle and I'll show you why.
We are going to our terminal. So here we are running the migrate and we are going to get an error that it can be used only with the Kaiselli adapter. So we need to
run MPX better o C cli generate. So we
are going to run that one and we are going to get a totally new schema inside of the O schema.ts. ts. So yes, we are going to create that one. And going here
now to o schema.ts, we can see that we have besides the usual user session account verification, we have organization, member and invitation
tables created inside of our author schema. So what are we going to do? I'm
schema. So what are we going to do? I'm
going to copy the entire schema from here and move it to our original schema inside of our schema.ts file. So I'm
going to paste it in right here. And
inside of our schema, I'm just going to add new tables organization member and invitation. So we are now exporting all
invitation. So we are now exporting all the tables. And now we can actually run
the tables. And now we can actually run our migrations. So let's go. Drizzle kit
our migrations. So let's go. Drizzle kit
push and this one is going to create inside of our database new tables. So
now it's done. So we can go now to neon and here we can see that we have account session user verification and if we refresh here it is. So now we have new
tables organization member invitation, and this one is pretty much ready for us to create our organizations. Let's return to our
organizations. Let's return to our documentation right here. And next thing we need to do is to add the client plugin inside of our oclient.ts file. So let's open that one.
file. So let's open that one.
Oclientient.ts.
Here we are going to put the plugin for organizationclient and we are going to import it from /client/plugins.
So that one is done and we can also delete the o schema.ts. We don't need that one because we copy pasted everything to our schema file right
here. And that's it. We successfully
here. And that's it. We successfully
implemented better o and everything that is left is to actually use the organizations now. So we have the API
organizations now. So we have the API here for creation of new organizations.
When we run this one, this organization is created on our current user that is creating it and that user is set as
owner. So let's now create the form for
owner. So let's now create the form for actually creating our new organization and putting it inside of our database.
So we are going to our dashboard page and here we are going to create a new button and that button is going to create new organizations for us. So here
I'm putting in the button from shed CN create organization like this we are now here going to implement dialogue from shed CN. So
let's here open the dialogue and we need to install it inside of our project. So
I'm running the mpxian latest add dialogue command and then we are just going to import this one inside of our
page right here and also the usage.
We're going to put it under the button.
And then I'm going to take this button and replace this open text and put as child. So that button is used for
child. So that button is used for opening our dialogue. So if we go to the project right here, we can see the create organization button and we are
just going to put here a little bit of gap and we are going to put this button to variant outline so it matches this one and if we click it we are opening
the dialogue. So that one is working
the dialogue. So that one is working fine. Now we need to create a form which
fine. Now we need to create a form which we are going to put inside of this dialogue. And inside of our components
dialogue. And inside of our components we already have the forms directory. So
there we're going to create a new create organization form.tsx
organization form.tsx and here we're going to use react hook forms. So we are going back to shed cn and we are searching for forms. Here it is. We already have it installed because
is. We already have it installed because we are using it for login signup and other things. So we can just start from
other things. So we can just start from here. So I'm adding here the use client
here. So I'm adding here the use client importing zod and our form schema. So we
can return to our better off. We need
name and slug and logo. We're going to skip logo for now. So let's put in just name and slug. Those are both
just strings. So here we're putting name
just strings. So here we're putting name and also slug like this. Then we can return to shed cnen documentation. We
need to add zod resolver and use form.
So adding that one here on the top of our file and we are also adding the form and onsubmit inside of our component. So
I'm going to copy the whole component from here. We are just going to call it
from here. We are just going to call it create organization form. Here we are putting name and slug. I'm going to remove these comments from here. And
last thing, we just need to add our forms button and inputs. We are
importing that right here. And we are putting it in inside of our component.
So here we are just going to add return brackets and we are returning our form.
We are going to put here the name instead of this username and we're also going to add slug.
So here we're letting AI do its thing.
Nice. So here we have I'm just going to put my org for the placeholder. We can
remove the descriptions. We don't need that one. And here we can remove the
that one. And here we can remove the import also to remove this empty space. Nice.
So this one now looks good. Only thing
left is here on submit. We need to put that API from better o. So it's this one. Let's copy it and paste it right
one. Let's copy it and paste it right here. So we are just going to leave this
here. So we are just going to leave this logo to be hardcoded. This function
needs to be an async function.
Okay. And we're putting values and slug to be the values from our form. And
we're also going to put here a try catch.
And we need some toast messages. So here
we're going to put toast success.
Importing toast from Soner. And also
here we need toast error. And we are going to add quickly one loading state is loading.
AI knows exactly what I need. So we
added is loading. And we are going to put it set is loading here to true. And
finally to set it as false. And on our button we are going to put it to be disabled while loading. And instead of creating text, we are putting loader
two. And that one is just going to be
two. And that one is just going to be size four and animate spin. And now we just need to put this form inside of our dialogue. So here we're going to change
dialogue. So here we're going to change the title to create organization and description as well. So here we're
going to put our form inside of that dialogue. And now it's ready to be
dialogue. And now it's ready to be tested. So we are going back and here
tested. So we are going back and here creating organization. It's opening our
creating organization. It's opening our form right here. Let's just put this spacing to a little bit less like this
for nice. And now we can create our new
for nice. And now we can create our new organization. So I'm going to create my
organization. So I'm going to create my organization and I'm going to put my org as slug. And we are creating our
as slug. And we are creating our organization. And we are going to get
organization. And we are going to get the toast organization created successfully. Nice. So if we go to our
successfully. Nice. So if we go to our database and we go to organizations, we can see that it is really created successfully. We have everything here
successfully. We have everything here and inside of our members, we can see my user ID and I'm the owner of the organization. We have also the
organization. We have also the organization ID. So the whole logic is
organization ID. So the whole logic is working perfectly well and we can now actually know in which organization am I
inside of our application right here. So
we can now display our active organization here and we are also going to create a switcher that we can choose which organization is currently active.
So if you get back to better o documentation we can see here that we have API also for setting the active organization and we need to say we need
to send the organization ID. So we are going to use this one. We can also use the slug if that one is easier but we are just going to create server action
where we are going to get all our organizations. So let's create server
organizations. So let's create server actions for our organizations. Here we
have the server directory. Inside we
have users. And we are going to create organizations.ts.
organizations.ts.
Here we are going to create a new method get organizations. And this one is bad.
get organizations. And this one is bad.
AI doesn't know what is he doing. So we
are going to add here use server because these are server actions. And we need first our current user that is logged
in. So to do that we are going to now
in. So to do that we are going to now this is good. So we need session from our current user and for that we need
headers. Here it is like this. So we are
headers. Here it is like this. So we are going to import headers from our next headers. And now we have the session
headers. And now we have the session from our current user. And if there is no session we are just going to redirect
our users to /lo. That one sounds like a good idea. Then here we are going to
good idea. Then here we are going to call our current user from our database just like this. So we are going to import database from Drizzle equals from
Drizzle OM and user from our schema here. So now we have the current user
here. So now we have the current user which is currently logged in and if he's not there we are just going to again redirect to our login and this is
something that we are going to use many times. So this is really good to create
times. So this is really good to create a new here for example get current user method and there we put just this one
and we return that session and our current user. So here we just
need to import of course all these dependencies that we need and this user here as well equals from
Drizz and DB from Drizzle. Nice. So now
we can get our current user instead of this we can just say current user equals get current user from the users.ts
server actions file. And now we can actually find our organizations. And to
do that we first need to find members where our user is in the database. So
for that we are just going to search for our user ID. And then for organizations we are going to check how many
organizations are there for our user.
And this one is going to return all the organizations that we need and that our user is part of. Just one word of caution, you can use of course the API
for this. So here on better o we have
for this. So here on better o we have list users organization but this one is using o client and this one can be used only in client components. Our case
right here that we created can be used in server components and it's much better of course because all data here is cached and you're calling it only
once. So I prefer more to call it from
once. So I prefer more to call it from the server actions like this to have it working on server components. But if we
need it, of course, we can call this one in client components if there is some case that we need to list our user organizations. And we can now inside of
organizations. And we can now inside of our dashboard page call our organizations. So here we are calling
organizations. So here we are calling get organizations. We have our user here
get organizations. We have our user here logged in. We need to turn this into an
logged in. We need to turn this into an async function in order to wait it. And
here we can for example list our current organizations.
So we can just put it like this to see if it's working or not. And now here we can see that we have my organization listed. So this is coming from our
listed. So this is coming from our database. And that one is working just
database. And that one is working just fine. Awesome. So let's now remove this
fine. Awesome. So let's now remove this list here and we are going to create the organization switcher. So, we are going
organization switcher. So, we are going to put it inside of our header. So, I'm
opening the header. This one is imported inside of our main layout. So, I'm going to take this header from here and put it
on our main page because we don't want the organization switcher to be seen when the user is not logged in. So this
one is going to be just for the main page but the layout we need to remove the header from here and we are going to
create a new layout inside of our dashboard directory. So here creating
dashboard directory. So here creating layout.tsx
layout.tsx and we are going to put here children and header right here. So if we
now go to our project, we still have the header. But if we type in something
header. But if we type in something here, this one is seen in our dashboard.
But if we go to our local host, it's not there. So that one is working great.
there. So that one is working great.
Awesome. And we can now put here our organization switcher inside of our header. So for that we need select. I'm
header. So for that we need select. I'm
going again to shed CNN and we are typing in select. Then we are going to
implement it inside of our terminal and we are just going to add it. So
first let's create here inside the components the organization switcher.
Organization switcher.tsx DSX
switcher.tsx DSX and here I'm going to put the select and also I'm going to copy the usage right here. So we can export organization
here. So we can export organization switcher and here put the usage inside of our component and this component is going to
be a client component because we are going to use the O client from better o in order to set our active organizations. So we are going to the
organizations. So we are going to the better o API and here we have set active organization. So I'm just going to copy
organization. So I'm just going to copy this one and I'm going to create a new handle change organization. So we are sending
change organization. So we are sending the organization ID and we are just going to use this one. So I'm going to import client like this and instead of
this organization ID, we are just going to pass the organization ID from our select. So now here we need
select. So now here we need organizations and we picked that one up with our server actions. So here I'm going to create a new interface
organization switcher props and we are going to import the organizations for this one inside of our schema.
And if we go to organizations here I'm going to export type organization and that one is going to be infer select
from our table right here. So now if we go back to our switcher, we can import the organization type from our schema
right here. So we know exactly what are
right here. So we know exactly what are we receiving as props inside of our organization switcher. And here we can
organization switcher. And here we can map through our organizations. And on
our select we can put on value change handle change organization and default value is going to be our current
organization. And to get that one, we
organization. And to get that one, we can here use use active organization. So
I'm going to copy this one and we are going to put it inside of our component here active organization. And we are
going to put for our default value active organization ID. And now if we go to our header and put in the
organization switcher right here, we're also going to call organizations inside of our header. And we can remove that organizations
from our page. It is is it already removed from our dashboard page actually here? Yeah, we can remove this one. We
here? Yeah, we can remove this one. We
don't need it. And if we go back to our project, we have here our organization picker and we can see already that we
have actually my organization inside of our select box. So if I refresh, we are not getting yet the current organization. Let's see what's wrong.
organization. Let's see what's wrong.
Let's add first the try catch inside of our handle change organization. So here
I'm going to put try and catch here and also toast if something is wrong and here success if we switched our
organization successfully and there is also an error from the better off API. So we can here return the error in case there is one. So let's
try again. Now here I'm going to change the organization my organization organization switched successfully. So
it is working. Maybe it's because we don't have other organizations. So let's
create a new one here. I'm going to create orcs and slug is going to be orcs. Create organization.
orcs. Create organization.
Awesome. So we created a new one. And
now here we can see the new organization inside of our select. And if we select it, organization switched successfully.
Nice. But it's still not showing the current one. Okay. So we need to change
current one. Okay. So we need to change something. Let's first in our header put
something. Let's first in our header put here justify between. So this one is actually on the left and we probably
need with full here. There it is. Nice.
So we have now our switcher right here.
And we need to just see our current active organization. It's an interesting
active organization. It's an interesting bug we have here. So let's try to display actually our active organization. So here I'm going to put
organization. So here I'm going to put if active organization just to display it. And here I'm going to close my
it. And here I'm going to close my fragments. So let's see if we have it.
fragments. So let's see if we have it.
Okay. So we have our current organization here displayed. So that's
good. It's not the problem with the API.
is a problem with our oh it's here instead of default value we need just value and now I think it's going to work so if I refresh yeah now we have works
nice so if I choose my organization then organization switch successfully successfully and if you refresh we are getting again my organization and that
one is working properly now and we need to add one more thing when the user logs in active organization by default is null
So there is one really great database hook here. It is that is helping us to
hook here. It is that is helping us to set the active organization to whatever organization we want. So we are going to our o.ds
our o.ds and here we are just going to put our database hook. So here we are getting
database hook. So here we are getting the organization get active organization. Basically we need to
organization. Basically we need to create this method for us. We have the session with the user ID. So everything
we need to do is just to get the first organization that we can with the get active organization. So we are going
active organization. So we are going again to our server actions file and here we are going to create a new get active organization method and here we
are getting the organization by the organization ID. This one is not good.
organization ID. This one is not good.
We need our actual member user and we are going to get it from our member table with our user ID. And then for our
active organization, we are just going to take the first organization that we can by our member user organization ID.
So now we can get back to our o.ts and here everything is set. So we have our get active organization.
So now we can get back to our o.ts and we are going to import get active organization. Here we are just going to
organization. Here we are just going to put a question mark and we can test it out. So here I'm going to log out. We
out. So here I'm going to log out. We
are going to log in again and we should get that my organization as our default organization when we are
logged in. Here it is and we have my
logged in. Here it is and we have my organization as the active organization.
So it's working perfectly. I hope you enjoyed warriors. In part two, we are
enjoyed warriors. In part two, we are going to work on members CRUD and roles who can create, delete, update organizations and other things. Some big
table with members that we can add, edit member, remove, leave the organization, etc. So, tell me in the comments below, how do you like this series so far? And
for more content like this, as always, join the mighty horde.
Loading video analysis...