Stripe & Firebase Tutorial • Add Payments To Your NextJS App

Stripe & Firebase Tutorial • Add Payments To Your NextJS App


Stripe & Firebase Tutorial • Add Payments To Your NextJS App

Want to collect monthly payments from your app or online business?

In this project, we will implement a monthly subscription payment system for our NextJS web app. We’ll be using Stripe as our payment processor, and integrate it with Google Firebase for user authentication.

🛠️ GitHub/Code: https://github.com/pixegami/stripe-fi

👉 Tech Stack
🔗 Firebase: https://firebase.google.com/
🔗 Stripe: https://stripe.com/
🔗 NextJS: https://nextjs.org/

🎬 Chapters

00:00 Introduction
01:52 Project Architecture
04:04 Authentication With Firebase
12:27 Setting Up Stripe For Payments
21:51 Adding a Checkout Session
29:17 How To Check Subscription Status
32:18 Adding Stripe Account Management
34:47 Wrapping Up


Content

0 -> Hey everyone! In this video, I'm going to show
2.443 -> you how to add a subscription payment
4.418 -> system to your web app so that you can collect
6.861 -> monthly payments from your customers.
8.785 -> This is useful if you want to build an app where
11.586 -> your business model is a fixed price monthly
14.158 -> subscription like Netflix, Spotify or Dropbox.
16.788 -> By the end of this project, you're going to build
19.761 -> an app where your customers can log in, buy a premium
22.973 -> subscription for $10 a month and manage or
25.531 -> cancel the subscription from their account page.
28.386 -> Here is our tech stack.
30.136 -> For the front-end, we're going to use NextJS to build a static website.
35.147 -> And then we're going to use Firebase for the
37.367 -> back-end, but mainly for the authentication.
39.539 -> And we're going to use Stripe to integrate the payments.
42.333 -> I'm going to show you how to integrate Firebase and Stripe into our app.
46.011 -> But I will expect you to already have some experience with NextJS.
49.509 -> To get started, go to this GitHub repository where you can download
53.311 -> the sample project and use the starting point branch.
56.276 -> You're going to get a skeleton of the project where all the UI
59.454 -> is there for you, but there's no functionality added yet.
62.331 -> Once you've downloaded the repo, go into the project
65.716 -> directory and run "npm install" or "yarn
68.335 -> install" to get all of the dependencies added.
71.274 -> Once everything's installed, type in "yarn dev" or
74.557 -> "npm run dev" to start the development server.
77.52 -> Once the local server is up and running, you should be
81.05 -> able to visit this local URL and see the project.
84.195 -> So it will be a home page and there'll be a button to log in.
87.205 -> Nothing really works yet, but we can click around.
90.053 -> And our goal is to add authentication to this app so that you can log in.
94.72 -> And then when you log in, we also want the member
97.47 -> to be able to upgrade to a "premium" account.
99.945 -> Or if they're already a premium member,
102.145 -> for this status panel to show that. And also
104.675 -> for this button to change so that you can
106.985 -> manage or cancel your subscription instead.
109.351 -> And then you can also sign-out as well.
111.502 -> Before we begin, let's just spend a moment talking about our project architecture.
116.16 -> So we're going to have our users interact with the front-end,
118.8 -> which is just going to be a React or a NextJS website.
121.181 -> And we're going to use Firebase for authentication.
123.798 -> Now, once we're authenticated, we're also going
126.013 -> to set up a Stripe account and we can connect
128.136 -> to that directly with the front-end as well.
130.167 -> This is one of the ways that we can do it, but we're not going to do that.
133.976 -> Another option is if we had some kind of backend in between
137.443 -> the front-end and Stripe, for example, it could be
140.39 -> a Python backend, or it can be a Lambda function on AWS.
143.626 -> We can also have the front-end talk to the backend
146.429 -> and then have the backend talk to Stripe directly.
149.178 -> And the backend might also want to talk to Firebase directly
152.409 -> to make sure that you are an authenticated user.
154.953 -> And this is probably a better design because we want
157.747 -> the backend to know about the payments, the
160.068 -> subscription, and the authentication, Because ultimately
163.073 -> it's probably the back-end side of the
165.13 -> service that will provide value for our customers.
167.767 -> And I would generally go with a design like this, but this
170.487 -> is a little bit too complicated for this project today.
173.023 -> So we're going to do something even simpler.
175.056 -> We're going to have our users interact with our
177.215 -> static website, which is going to be in NextJS,
179.33 -> and that's going to talk to Firebase.
181.04 -> So we're going to have an integration with Firebase there.
183.987 -> And Firebase is where we authenticate our users.
186.471 -> But because authentication and payments are quite
189.573 -> closely related to each other, like we
191.992 -> need to know which authenticated users are paying
195.094 -> for what subscription, it's probably better
197.824 -> to connect Firebase directly to Stripe.
200.244 -> So we don't have the front-end kind of acting
202.899 -> like a middleman between these two services.
205.44 -> Luckily, Firebase gives us a really easy way to integrate with Stripe.
209.229 -> So we're going to use that, have Firebase connected
212.161 -> with Stripe, and then we're going to interact with
215.036 -> our payments, our authentication, our backend,
217.63 -> everything through Firebase directly from NextJS.
220.45 -> So this is what we're aiming to build.
222.583 -> Now, the reason I chose these three technologies
225.048 -> in particular is because they're quite popular
227.414 -> and they're quite good at what they do.
229.377 -> So NextJS is a very popular front-end framework.
231.853 -> Firebase is also really popular for authentication and it's free.
235.677 -> And Stripe is also the most popular option for payments processing.
239.751 -> These three technologies also work really well together as a combination.
243.807 -> For the first part of this project, let's first
246.406 -> get our authentication working with Firebase.
248.844 -> First, you need to head to "firebase.google.com" and then log
252.092 -> in with your account or sign up if you don't have an account.
255.289 -> Once you've done that, you should go to the Firebase
257.973 -> console where you'll see a list of your
259.999 -> projects. Or you might not see anything
262.026 -> if you don't have any projects yet. And click
264.356 -> on this button here to add a new project.
266.433 -> And you can enter any name you want.
269.001 -> So I'm going to call this "Stripe-app" and then click continue.
273.847 -> And you can turn all this stuff on if you want,
275.932 -> but I'm just going to turn it off because
277.841 -> I don't really need it for this tutorial.
279.661 -> And I'm going to hit "Create Project".
281.436 -> And after a minute or so it should be done and you can just click continue.
285.364 -> So now you'll be taken to your project dashboard
288.068 -> and just scroll down and click on authentication
290.772 -> over here, go to the top and click get started.
293.367 -> And here Firebase basically provides all of the authentication backend for you.
298.039 -> So all you have to do is select what type of authentication you want.
301.513 -> For this one, I'm going to keep it really simple and
304.095 -> just choose Google as my authentication system.
306.385 -> And I'm going to click "Enable".
307.902 -> And you can just leave all of these as default.
310.306 -> You might have to put in a support email, and then you can click "Save".
313.892 -> And I don't really like to have my own list of user emails and
317.717 -> passwords because it's just more things for me to manage.
321.178 -> So unless I really need to, I try to build all these
324.482 -> apps with third party authentication like Google.
327.538 -> And once this is done, we've done everything we need to from the console.
331.735 -> So the next step is to create a Firebase client
335.002 -> from our NextJS app so that we can use this Google
338.474 -> authentication from our website and login.
341.333 -> So to do that, go back to the project overview.
344.397 -> And we're going to create an app here.
346.925 -> So here where it says get started by adding Firebase
349.912 -> to your app, you have a couple of options.
352.28 -> And we're going to go with "web" because the NextJS is a web interface.
356.128 -> And here again, just fill it in with whatever you want.
362.24 -> And I'm just going to register the app.
364.414 -> Once that's done, Firebase will show you some instructions
368.065 -> on how you can install the Firebase SDK
370.541 -> or the Firebase client into your NextJS project.
373.513 -> And also show you how to configure it with all
376.23 -> your API keys and your project settings.
378.543 -> So let's go ahead and bring this into our project.
381.146 -> We're going to install the Firebase SDK.
383.142 -> And we're also going to install React Firebase
385.469 -> hooks because we're going to need that later.
387.697 -> And I'm using yarn, but you can also use "npm install" if you prefer that.
391.314 -> So go back to your terminal and type in "yarn add firebase"
395.274 -> and "yarn add react-firebase-hooks". Or "npm
398.244 -> install" instead of "yarn add "if you're using npm.
401.611 -> And then hit enter. Once that's done, open up the project in your code editor.
406.56 -> And you should see all of the project code here.
410.312 -> So there's a source directory, an app, and then there's two pages.
415.185 -> So the main page and the account page.
417.676 -> And that's basically it at this point.
420.136 -> Every button in here is basically just a redirect.
422.632 -> So there's no functionality yet.
424.274 -> So we're going to add the login.
425.971 -> But first we need a Firebase client in our app.
428.424 -> So go to the source directory and create a new file there.
432.367 -> And I'm just going to call this one firebase.ts.
436.029 -> And if you go back to your Firebase console,
438.961 -> we'll just copy this whole client configuration
442.228 -> here and just paste it into that file.
444.761 -> So now we have this "app" variable that we
447.723 -> can import into our other files, and it will
450.823 -> give us an instance of the Firebase SDK.
453.579 -> But I don't like to use this directly.
455.84 -> Instead, I like to actually wrap it up in a getter function or something like this.
461.286 -> So a function called "initFirebase".
463.703 -> And that's because when I retrieve a singleton from
466.946 -> a class like this, I prefer to have a method that
470.066 -> I can change if I wanted to behave differently.
472.998 -> So I like to wrap it up.
474.46 -> And this way, we'll just use this instead.
477.149 -> And it will just return whatever this is.
479.827 -> Or if we need to change how we initialize it, we can modify it here.
485.153 -> Now go over to our page.tsx and make sure that
487.742 -> this is the one in the app directory and
490.002 -> not the one in the account directory, because
492.537 -> that's going to be the account page.
494.521 -> So go to the homepage and page.tsx.
496.429 -> And we're going to import and initialize Firebase.
499.425 -> So here, I'm going to call it "app = initFirebase".
503.785 -> And make sure that it imports it from the file
506.867 -> we just created here like that as well.
509.425 -> And this is going to be the Firebase SDK instance.
512.215 -> So we can make calls to Firebase, the one that we created using this app.
515.952 -> And the first thing we're going to do is user sign in.
518.613 -> So to do that, we're going to need a couple more
521.365 -> pieces, and I'm going to import them here.
523.725 -> So we're going to import getAuth, GoogleAuthProvider, and signInWithPopUp.
529.007 -> And this is going to be all from "firebase/auth", which we
532.446 -> should already have installed with our Firebase library.
535.711 -> So we are going to create an auth instance.
538.82 -> And then we just basically call get auth and pass in the SDK that we just created.
544.217 -> We're also going to create a GoogleAuthProvider.
547.633 -> So make sure that you have these three lines added.
551.304 -> And once that's done, we can now modify our sign in function,
555.115 -> which currently just redirects to the account page
558.365 -> to actually do the sign in for the user with a pop up.
561.74 -> So we're going to store the result of the sign in.
564.813 -> And this is an async function, sign in with pop up.
567.48 -> So we're going to need an "await" here, we just
570.464 -> pass in the auth object and the provider.
573.013 -> And once that's done, we also want to get the user.
576.996 -> So the result is a user credential.
578.628 -> And if you want to see what it has, you can just click through.
581.86 -> But if it's signed in successfully, this should be non-null.
585.767 -> So if the sign in is successful, and the user
589.691 -> is not null, we can then go to the account.
593.361 -> Let's go back to our browser to test it out.
596.836 -> So make sure you still have your local development server running.
600.202 -> And you can just refresh the page as well to make sure that it
603.034 -> has all the latest changes and then click "Login with Google".
605.823 -> And now you should see this pop up, prompting you to choose a login.
610.38 -> So if you click on one of your accounts, it should sign you in.
614.397 -> And now you should be taken to this page.
616.957 -> But now let's also implement the sign-out button.
619.867 -> And let's actually make these things update based on the user.
623.462 -> Go back to your code editor.
625.044 -> And this time, we're going to go to the "account" page.
628.09 -> So go to "account" and then open page.tsx inside account.
631.832 -> And here you can see I've hard-coded all the user credentials.
635.591 -> First, we're going to need to initialize the app and authentication as well.
639.43 -> So just copy those two lines from the previous page and
643.53 -> make sure that you have all the imports as well.
647.045 -> And once this is done, we can get the username
651.331 -> and the email from "auth.currentUser".
654.798 -> So we can do it like this.
657.648 -> And if you save that and go back to the page, we can
661.921 -> check whether or not those fields have been updated.
666.114 -> So now it's updated to the actual Google account that I signed in with.
669.634 -> So that's good.
670.275 -> Now we also want to make this sign-out button work.ß
672.569 -> So let's go back to the code.
674.504 -> And here we have our sign out function.
677.148 -> And to implement the sign out, all we have to do
680.003 -> is just call this auth object that we imported.
682.742 -> And it has a "signOut" function.
684.609 -> So that's pretty simple.
686.254 -> Go ahead and hit save.
687.507 -> And then I'll go back to my browser and hit "Sign Out".
691.049 -> And it's taken us back to this page.
692.704 -> And we should also be signed out.
694.249 -> And that pretty much does it for the authentication.
697.368 -> I actually also added something called an "AuthRouter" here.
701.406 -> So this is just a class that basically, when you go to this
705.172 -> page, it's going to check what the path you're on.
708.311 -> And if you're logged in or not automatically, and
710.493 -> vice versa, if you go to the homepage, but you are
712.72 -> logged on, it's going to go to the account page.
714.816 -> I'm not going to go into detail of how to implement
717.13 -> this because it's not essential to the project.
719.182 -> But it is there if you want to use it.
720.878 -> And it's there in the GitHub repository as well, if you want to take a closer look.
724.524 -> So it's going to be part of the layout here.
727.049 -> And if you go to the page, and see I'm signed in right now, but
731.003 -> if I try to go to the homepage, it won't let me sign in.
734.464 -> And if I sign out, it won't let me go to the "account" page either.
738.332 -> So it just bounces me back to that.
740.267 -> So yeah, I just wanted to let you know that this is going to be in the GitHub repo.
744.683 -> But we're not going to go over this in any more detail.
747.365 -> Now that we can sign in and sign out of our app,
749.787 -> the next step is to set up the payment system.
752.16 -> And we're going to do that using Stripe.
754.037 -> Stripe is the most popular online payment platform in the world.
757.002 -> It lets you create and manage products that your
759.504 -> customers can pay for using their credit cards.
761.904 -> So to get started, first go to stripe.com.
764.706 -> And either sign in or create a new account if you don't have one already.
768.219 -> And once you have an account, you should be able to see your dashboard.
771.574 -> So make sure that you click on "test mode", because
774.278 -> this will put it into a mode where you can sort
776.774 -> of just go crazy and test it and use fake credit
779.322 -> cards just to make sure the whole system works.
781.766 -> And you can turn it back to production mode if you actually
784.551 -> want to switch on real payments and real credit cards.
787.058 -> But for this tutorial, let's just use "test mode".
789.684 -> And everything will work exactly the same.
791.923 -> And we're not going to need to do anything here yet.
794.583 -> But just get familiar with this page because we're going to come back to it later.
798.747 -> You can manage all your payments and customers and products here.
802.331 -> And you can go to developers here to get your API key, which
805.857 -> is what you'll need for Firebase to talk to Stripe.
808.806 -> So if you go here, you'll be able to see all your
811.458 -> API keys, web hooks, and all that stuff.
813.58 -> We'll get to that later on.
815.029 -> But just get comfortable with this page and make sure it's all set up.
818.713 -> Now remember, we went over this already, Stripe actually has a JavaScript library.
823.098 -> So we can connect Stripe directly to our NextJS app, and then
826.676 -> have a client and SDK and everything for that as well.
829.794 -> But again, we don't really want to do that because we still
832.855 -> need Stripe to be tightly integrated with Firebase.
835.458 -> The reason for that is if you go to your Stripe
837.906 -> customer dashboard, you'll see that the
839.947 -> customers created from Stripe actually have
842.192 -> different IDs to the Firebase customers.
844.233 -> So if you go to your Firebase app, go to your console, and then
847.354 -> authentication, you can see a list of your customers here.
850.184 -> And it's got this unique user ID.
851.717 -> But Stripe has their own completely different set
854.425 -> of IDs and customer authentication, but you
856.809 -> still need these two things to be connected.
859.193 -> So since it's not possible to separate those things
862.215 -> anyways, it makes more sense that we integrate
864.947 -> Stripe via Firebase in our web app, rather than
867.737 -> have our web app talk to each one separately.
870.353 -> However, if you are curious about Stripes front-end client,
874.529 -> you can go to stripe.com/docs/js, where you can
877.997 -> read about their react or their JavaScript library.
881.608 -> Now to integrate Stripe with Firebase.
884.248 -> If we did this manually, it'd be quite complex.
887.066 -> For example, we'd have to make sure that every
890.052 -> time a new user signs in with Firebase, we also
893.103 -> create a corresponding user in Stripe's account
896.153 -> system and somehow map those IDs together.
898.823 -> And we also need Firebase's data.
900.897 -> For example, if you're using the database to have updated
904.541 -> information about that user. Like if they're subscribed
908.059 -> or not, or when their last login was, etc.
910.699 -> So a bunch of different things need to be coordinated between the two.
914 -> And this is quite complex if we had to build it ourselves.
916.84 -> But luckily, Stripe has actually built an extension for Firebase.
920.048 -> So we can pretty much get all of that for free with a click of a button.
923.6 -> So let's see how to do that.
925 -> So go back to the Firebase project dashboard
927.547 -> for your app, and go to authentication.
929.755 -> And here there's this tab called "extensions".
932.886 -> So click on that.
934.141 -> And here you can browse a bunch of different extensions
937.495 -> made for Firebase by different companies.
939.951 -> And you're looking for this one called "Run Payments
942.47 -> With Stripe", and it's made by Stripe.
944.277 -> So if you don't find that you can search for it,
946.523 -> but it should be here on the front page, and
948.677 -> then just click install, you'll then be taken
950.83 -> to this page to configure the extension.
952.703 -> And the first thing it's going to ask you to do is set up billing.
956.226 -> That's because when you use this extension, it creates
959.335 -> a whole bunch of other resources, like cloud
961.88 -> functions and databases. But you probably
964.254 -> won't get charged anything for this, because it
966.968 -> typically takes millions of calls to the services
969.796 -> for it to exceed the free tier that you get.
972.284 -> So you get something like 1 million free users per month.
975.04 -> So don't be intimidated by this plan.
976.786 -> However, to get to the next step, you do need to add a credit card.
980.002 -> So go ahead and do that and then click "upgrade project" to continue.
983.289 -> And then just click "continue".
984.828 -> And you can also set a budget amount so that you
987.655 -> get alerted when it hits a certain amount.
990.08 -> And here I'm just going to set $50, but I don't
992.463 -> think it's even going to cost anything.
996.56 -> And now the next step, you're going to be notified of
999.384 -> all the resources that this extension will create.
1002 -> You might actually have to enable each of these things
1004.988 -> if they haven't been ready for your account.
1007.38 -> But apart from that, you don't have to do anything yourself.
1009.974 -> So you can click "next".
1011.282 -> And then you're on to step three, you can review the access granted.
1015.696 -> Again, not much for you to do, just click "next".
1018.177 -> And in step four, you'll get prompted to configure your extension.
1021.92 -> You get to choose your deployment location.
1024.833 -> So you get a bunch of options here.
1027.248 -> It doesn't really matter for me, I'm just going to choose "us-central-1".
1031.067 -> And then you can leave all of these as default.
1033.348 -> But if you want to change them, then mouse over
1035.768 -> this tooltip to read more about what they do.
1038.037 -> And finally, we're going to need this Stripe API key.
1041.51 -> So we'll go to our Stripe dashboard, click on "developers".
1045.14 -> And again, make sure that it's enabled in "test mode".
1048.308 -> And on the developer page, you should be able to see this API key tab here.
1052.202 -> So click on that you have the secret key, which it just gives
1055.119 -> Firebase full access to everything on your Stripe.
1057.473 -> So you can use that as well.
1058.796 -> But if you want to be more secure, you can create a restricted key instead.
1062.386 -> So this is like a key that only lets Firebase do certain things.
1065.47 -> And you can do that by clicking this "create restricted
1068.392 -> key" button, and just making sure that it has
1070.793 -> all of the permissions that Firebase asked for.
1073.247 -> So customers, checkout sessions, and whatever it says here.
1076.332 -> So you can go and create this or you can use this
1079.129 -> one, but I've already created a Firebase key.
1081.648 -> So I'm just going to use the one I've already created, click to copy it.
1085.44 -> Now this is a secret key.
1086.64 -> So if you're doing this for real, then make
1088.923 -> sure that this doesn't get committed to public
1091.363 -> GitHub repo or that anyone can see this.
1093.44 -> For this video, it is a test and I will delete this key afterwards.
1096.678 -> So that's why I can show it now.
1098.252 -> But if you're doing this for real, then make sure that
1100.69 -> this key doesn't get revealed to anyone else.
1102.685 -> Once you've copied the key, just paste it in here and then click "Create Secret".
1107.237 -> After a while, it should finish.
1109.092 -> And now you have the key configured.
1111.093 -> We'll also need a Stripe webhook, but you actually
1113.852 -> can't get one yet until this extension is created.
1116.557 -> So we're just going to skip out everything and click "Install Extension".
1120.278 -> And this usually takes a couple of minutes.
1122.519 -> So we're going to have to wait a while.
1124.204 -> When the extension finished installing, you can
1126.601 -> click the "Get Started" button and you'll see
1128.898 -> instructions and resources on how to use it.
1131.096 -> So here it says that there is a client SDK so that
1134.131 -> we can interact with it from NextJS quite easily.
1137.047 -> We'll get to that in a second, but there's also instructions
1140.511 -> to finish configuring this extension.
1142.613 -> We'll have to set up Firestore, which is going to be
1145.19 -> our database, and we'll have to give it these roles.
1147.719 -> So let's go ahead and do that now.
1149.387 -> I'm just going to copy these roles over here and
1151.974 -> then we'll go over to our project, click on
1154.298 -> Firestore and then click "Create Database".
1156.569 -> And here I'm just going to leave it on default.
1159.318 -> And yeah, I'm just going to select the default location as well.
1162.827 -> When it's done, we'll go over to the rules tab
1165.504 -> over here and then replace this with the rules
1168.182 -> we copied over from the extension page.
1170.405 -> So highlight all of this and then delete it, paste all of the rules we just copied.
1175.054 -> Okay. And let's go back to our extension. So the
1178.018 -> next step is to configure Stripe webhooks.
1180.56 -> And you can pretty much just read these instructions
1182.747 -> and follow it yourself, but I'll show you how
1184.645 -> to do it so we can go through it together as well.
1186.709 -> First, we have to go to the Stripe dashboard, and we need this URL.
1190.665 -> So we're going to have to copy this.
1193.242 -> This is a specific URL to your Firebase app.
1196.194 -> Go to your dashboard and click on "webhooks".
1198.754 -> And you can see I have a couple created here already that
1201.527 -> I was testing, but we're going to make a new one.
1203.871 -> So click "Add Endpoint".
1204.88 -> And here you can paste that Firebase URL you just copied.
1207.951 -> And here you're going to have to select events to listen to.
1211.531 -> So the webhook is kind of like a way for Stripe
1214.617 -> to tell Firebase when something has happened.
1217.511 -> If you click "Select Events", you can see all of these
1220.496 -> different events that can trigger this webhook.
1223.048 -> So for example, things like the balance changing or when the account is updated.
1228.264 -> If you go back to the Firebase extension page, there's
1231.341 -> a list of all the events that you need.
1233.524 -> And it's a little bit tedious, but I recommend
1236.237 -> just adding them because even though you can click
1239.181 -> "Select All Events", this is probably going
1241.722 -> to send too much data to your cloud function.
1244.32 -> And you don't really want to give a webhook or
1247.168 -> anything really more events, more permissions,
1249.956 -> or capabilities than it needs to do its job.
1252.684 -> It's just kind of not necessary.
1254.613 -> So it is a little bit painful, but go ahead and add each of them in.
1258.136 -> So for example, here we have product created, updated, and deleted.
1261.413 -> And if you go to the dashboard and type in one
1264.018 -> of those things, you can just select each one.
1266.568 -> So here I've clicked to manually add all of those events that
1269.912 -> Firebase told us, and I'm going to click "Add Events".
1272.826 -> And here you can double check to make sure you've got everything.
1275.799 -> And once that's done, just hit "Add Endpoint".
1278.053 -> And now your endpoint should show up here.
1280.262 -> So to take this webhook back to the Firebase extension,
1283.213 -> we're going to need the signing secret.
1285.36 -> So click to "reveal" this and then copy this entire string
1288.857 -> and then go back to your extension page. Go to "extension
1292.296 -> configuration" and click "Reconfigure Extension".
1295.201 -> And now you can attach that webhook secret to this extension.
1298.917 -> So we'll hit "Create Secret".
1300.507 -> And when this is done, scroll all the way up and click "Save".
1304.084 -> Once the extension is done updating, we're pretty
1306.73 -> much finished with this part of the integration
1309.27 -> and we can continue building out our app.
1311.44 -> The first thing I want to do is adding a checkout
1314.33 -> session or a checkout button for our app.
1316.701 -> So let's go back to our Stripe dashboard.
1319.079 -> And first, we're going to need to create a product for our users to buy.
1323.204 -> So go to products, and then click "Add Product" over here.
1326.658 -> And here I'm just going to type in "stripe test product".
1329.93 -> And you don't really have to fill out all of these things yet.
1333.228 -> But you can if you want to.
1334.809 -> We'll scroll down, I'm going to set the price to $10 AUD.
1339.176 -> And it's going to be "recurring" because I want it to be a monthly subscription.
1343.112 -> And that's pretty much it.
1344.366 -> You can configure all these things if you want to, but I'm happy with this.
1347.634 -> So I'm going to click "Save Product".
1349.2 -> And now we have it here.
1350.629 -> And we have this price ID as well that we're going to need later.
1354.558 -> So just keep this in mind.
1355.996 -> This is where you can find it.
1357.576 -> Now on the extensions page, if you go to API and resources,
1360.752 -> there's actually a list of all the different functionality
1363.982 -> that we gained from making this integration.
1366.352 -> So now instead of calling Stripe directly, we can
1369.314 -> call Firebase and we can create customers, create
1372.276 -> checkout sessions, or even create a customer
1374.942 -> portal link for them to manage the subscriptions.
1377.845 -> So we can do all of these things.
1379.341 -> Now to actually use the Stripe Firebase extension in our app, go
1382.978 -> back to the documentation and read how this extension works.
1386.336 -> The top recommendation is to use this client SDK.
1388.996 -> It actually looks really nice.
1390.574 -> For example, we can create a checkout session with just three lines of code.
1395.04 -> But unfortunately, I tried this and it didn't
1397.942 -> work because this extension is 2 years old.
1400.656 -> And I don't think it was updated to use the newest Firebase API.
1404.614 -> So all of this stuff is a little bit out of date.
1407.531 -> So you can either roll back your Firebase version to
1410.211 -> the older version, but I don't think that's a good
1412.791 -> idea because you might get bugs or security risks.
1415.321 -> Instead, I'm going to basically just re-implement this API and
1419.261 -> call the Cloud Functions directly, which you can see here.
1422.889 -> Now, if you scroll down further in the docs, there's
1426.19 -> actually code examples as well on how
1428.557 -> to do all this stuff that the SDK does for us.
1431.423 -> So for example, here, we can create a checkout
1434.391 -> session and this actually has the raw JavaScript
1437.485 -> code that doesn't need that Stripe SDK.
1439.949 -> So we pass in the price ID here and then we get all of this stuff.
1443.745 -> Again, because this was done with the previous version
1446.723 -> of Firebase API, I don't think this works
1448.998 -> either, but I copied this whole thing into ChatGPT
1451.76 -> and asked it to convert it to the latest version
1454.414 -> of the Firebase API and that seemed to work.
1456.797 -> So to add the checkout, let's go back to our
1458.894 -> code now and go to the "account" folder.
1460.758 -> So I'm going to create a new file in here, which
1463.719 -> I'm going to call "stripePayment.ts".
1465.956 -> And this is going to be the utility class that
1468.816 -> interacts with Stripe through Firebase.
1471.19 -> And I'm just going to paste the code here.
1473.609 -> So it's not important to be able to write this
1476.772 -> from scratch because this is quite fiddly.
1479.6 -> So I recommend just copying this from my GitHub repo
1482.463 -> or pausing the screen and then copying the code
1485.056 -> directly, but I'll go through quickly what it does.
1487.811 -> So we've created a function here called "getCheckoutUrl" and
1490.895 -> we're going to need the Firebase app and the price ID.
1493.626 -> Then we're going to get the user, return it
1496.091 -> if there's no user, because obviously we can't
1498.724 -> do a checkout if they're not logged in.
1500.909 -> Then we're going to get the Firestore database and check for the checkout sessions.
1506.505 -> And if you go to Firebase and actually go to your Firestore,
1510.027 -> you'll see that once you start signing in
1512.552 -> with users, it actually creates a bunch of things
1515.487 -> for you, like customers here and products as well.
1518.423 -> So this is all being kept in sync at Firebase right now.
1521.516 -> And one of the things that we have on the customer is things like
1525.088 -> a Stripe link and checkout sessions and things like that.
1528.174 -> That's where it gets it from.
1529.626 -> So we go back to the code and now we're going to create a checkout
1533.194 -> session and this will basically give us a checkout URL.
1536.123 -> So I'm not sure what all of this stuff does behind
1538.96 -> the scenes, but basically we need to return
1541.409 -> a promise that will resolve into our URL.
1543.691 -> And that's going to be this thing here.
1545.719 -> Again, there's not much value in trying to learn what all this does.
1549.128 -> It's like once you write it once and it works
1551.176 -> and you can test it, you're pretty much done.
1553.181 -> So just copy it, or maybe Stripe has fixed their SDK by
1556.075 -> then and you don't need to go through all of this.
1558.659 -> So now I have that functionality.
1560.436 -> Let's go back to our account page and let's change
1563.507 -> this upgrade to premium button because right now on
1566.639 -> the test site, this doesn't really do anything.
1569.471 -> Like if I open the inspect tab and I press this, it just logs
1573.688 -> upgrade to premium, but it doesn't actually do anything.
1577.497 -> So let's go to here and let's create our price ID first.
1581.2 -> So a price ID, we can get that from our Stripe
1584.167 -> dashboard, go over to your products and
1586.693 -> copy this and we'll paste that as a string.
1589.409 -> And now we'll create a checkout URL.
1591.504 -> So I'm going to call it checkout URL, and I'm going
1595.394 -> to copy that function I created in the other file.
1599.135 -> And this needs an instance of our app, which we already created here.
1603.517 -> So pass that in and then pass in the price ID as well.
1606.915 -> So this is an async function.
1608.611 -> So we'll need an await, but once that's done, we should
1612.335 -> get a URL here and then we can just use the next
1615.594 -> navigation router to direct to that checkout URL.
1618.854 -> So hit "save" and make sure that the router you're
1621.721 -> using here is from "next/navigation", because
1624.308 -> there's also a use router from "next/router",
1626.838 -> but I don't think that's the one we need.
1629.2 -> So just make sure that it is this router from "next/navigation"
1632.594 -> and I'm going to hit "save" and
1634.292 -> go back to our site and actually test that out.
1636.785 -> So here I'm back on the site to test it out and you can
1639.665 -> click refresh just to make sure it has all the changes
1642.494 -> properly loaded in and click "upgrade to premium".
1645.066 -> And nothing might happen at first.
1646.556 -> It might take a while because it has to run a cloud function
1649.406 -> and get all the data from Stripe and all that stuff.
1651.837 -> But eventually it should take you to this checkout
1654.697 -> page and you can see it's all here.
1656.66 -> It is in test mode and the product we created Stripe
1659.697 -> test product is showing up here at $10 per month.
1662.506 -> And here is where we can enter our credit card information
1665.52 -> and actually test the whole payment flow.
1667.615 -> But when you're in test mode, you can't use real cards because it's all fake.
1671.484 -> So there's actually a bunch of fake credit
1673.633 -> cards that Stripes provides for us to use.
1675.733 -> So go over to Stripe documentation, which is stripe.
1678.609 -> com/docs and just search for "test card".
1680.877 -> And here you get three test cards.
1683.65 -> So you can test a "successful payment" or "payment
1686.389 -> failed" or "authentication needed".
1688.269 -> So let's copy the successful payment card here and we'll go in and just enter that.
1692.636 -> And then for everything else, it doesn't matter what we enter.
1696.081 -> We can just put in anything and then just put in a name on card.
1699.425 -> And yeah, I think everything else should be okay.
1702.567 -> We might have to enter an address.
1705.196 -> And then click "subscribe".
1706.836 -> And once it's done, it should take us back to our
1709.496 -> page and we're actually already subscribed.
1711.784 -> So for example, if you go back here and then you go
1714.851 -> to home, you should see your fake subscription show
1717.918 -> up in the dashboard and you can click to see your
1720.867 -> customers, your balances and all that stuff here.
1723.758 -> And likewise in the Firebase database, you should also see
1727.655 -> some status being updated for this particular user.
1731.025 -> So for example, if you go to this customer here, which is the
1734.035 -> one I signed up as, there's different checkout sessions.
1736.754 -> There's different payment options now being stored
1739.286 -> in the database and you can even click "subscriptions"
1742.017 -> and see this new subscription we just created
1744.301 -> and see all of the data associated with that.
1748.49 -> So this is available to us directly in Firebase.
1751.301 -> We don't have to talk to Stripe directly to get this information.
1755.069 -> It's kept in sync by our extension.
1757.043 -> Now for this to be useful for our app, we need to talk to
1760.597 -> this database on Firebase to get the subscription status.
1764.091 -> So let's go ahead and do that next.
1766.362 -> Let's head back to our app.
1768.007 -> And I'm also going to create another file here called getPremiumStatus.
1772.753 -> And again, I'm just going to paste the code that I'm going to use.
1777.656 -> And once again, I don't think you need to know
1780.057 -> the full details of how this code works.
1782.102 -> It's pretty convoluted and you only need to do it once.
1785.376 -> So you can just copy the code, but let's just go over it really quickly.
1789.969 -> We pass in an instance of the app and we get
1793.071 -> the user from that instance of the app.
1795.76 -> We get a reference to the database and then we basically
1798.918 -> check that subscriptions item that we clicked
1801.467 -> through just now to make sure that there's
1803.85 -> actually an active or a trialing subscription.
1806.4 -> That's pretty much the core of what this function does.
1809.26 -> It waits to get that result and then return either "true"
1812.513 -> or "false" based on whether a subscription was found.
1815.486 -> So just to go back and show you again, it's checking
1818.772 -> this item for this particular user and checking
1821.749 -> that there is an active subscription.
1824.044 -> So go ahead and copy this from the repo or from
1827.277 -> the screen and let's use it in our app.
1829.905 -> So let's go back to the account page.
1832.036 -> So here I have the premium status of this app,
1834.583 -> which is a hook and I've set it to "false".
1837.021 -> And we need to update this based on the results of this function.
1840.745 -> Now we can call this "getPremiumStatus" function directly.
1844.539 -> It is an async function, so we need to do it in another hook.
1849.485 -> So let's do it like this.
1851.92 -> So the hook creates this async function and then calls it.
1861.453 -> And the async function itself-- first, it checks if there is a user.
1863.787 -> If there's no user, it just returns "false" automatically.
1866.663 -> Otherwise, it will call this with the app instance
1869.688 -> and try to get the premium status.
1871.705 -> And this array with the app and the user ID basically
1875.033 -> just means to use this effect again or to invoke
1878.052 -> this hook again if any of these value changes.
1880.888 -> And we're interested in that because if the app
1883.492 -> client changes or if the user changes, we probably
1886.259 -> want to check the premium status again.
1888.375 -> And once we have the premium status configured, the app should
1892.334 -> already update the status panel based on that information.
1895.98 -> So let's go back and check if that is the case.
1898.323 -> So now if I refresh my account, you'll see that I am a premium member here.
1902.035 -> And just to check that it actually works for non-premium members,
1905.75 -> I'm going to sign out and I'm going to log in again.
1908.781 -> But this time I'm going to use a different user where
1911.925 -> I haven't actually paid for the subscription.
1914.546 -> So I'm going to use this guest user.
1916.363 -> And then if I log in as a guest, I'm still a standard
1919.199 -> member and I still can upgrade to premium.
1921.406 -> But let's go back to our premium user.
1923.208 -> And the final thing we're going to want to do is that if
1926.011 -> you're a premium user, you're going to want to be able
1928.716 -> to view or cancel your subscription pretty easily.
1931.175 -> So this upgrade button has changed to a managed subscription button,
1934.255 -> but it doesn't work yet because we didn't implement it.
1936.792 -> So let's do that next.
1937.874 -> Adding account management is going to be the final touch for our
1941.164 -> app, which will let users manage or cancel the subscription.
1944.202 -> Luckily, Firebase and Stripe make it really easy for us to do this.
1947.98 -> In our Firebase Stripe extension page, there
1950.604 -> is actually this create portal link cloud
1953.054 -> function that we can use to get a URL for
1955.504 -> customers to manage their subscriptions.
1957.838 -> Go back to our project.
1958.899 -> And instead of creating a new file this time,
1961.072 -> I'm just going to use stripePayment because
1963.245 -> it kind of fits with the rest of this file.
1965.322 -> And again, I don't expect you to type out this
1968.145 -> code, but I have it already created here.
1970.608 -> So this is called "getPortalUrl" and just make sure
1973.634 -> that everything you have here is imported.
1976.079 -> So you need this getFunctions and httpCallable from Firebase.
1979.862 -> You can go to the top and import it like this, this from "firebase/functions".
1984.826 -> And either just copy the code from my GitHub or pause
1987.777 -> the screen and type it out. And make sure that
1990.346 -> your function region is also the same as the
1992.806 -> one that you selected when you created the app.
1995.375 -> So if you're not sure, go to Firebase and just check
1997.896 -> which region your cloud functions are in.
1999.847 -> And this is the name of the function we want to use.
2002.597 -> So "extension-firestore-createPortalLink".
2005.192 -> Pretty much this code just calls the function
2008.158 -> and returns the URL if it doesn't fail.
2010.674 -> So that's all it does here.
2011.923 -> And it's a little bit complicated, which is why I don't
2014.467 -> think it's worth memorizing, but that's what it does.
2016.876 -> So we take this function and let's go back to our account
2019.948 -> page and use it here in this manage subscription button.
2022.915 -> And it's going to be very similar to this upgrade
2026.527 -> to premium one, where we create a portal URL.
2029.779 -> Then we'll call our function, we'll import that
2032.792 -> and we'll call it with the app instance.
2035.303 -> And then we just push it into the router.
2037.565 -> Oh, and this is an async function.
2039.361 -> So you have to put "await" in front of that as well.
2042.104 -> So save that. And let's go back to our web app, go here.
2045.403 -> And I'm just going to refresh the page, make sure that it has all the changes.
2049.61 -> And now I can click manage subscription.
2051.51 -> And again, it might take a while because it needs to call the function.
2054.4 -> So this is a little bit slow.
2055.6 -> So if it's too slow for you, you can actually
2057.862 -> make it figure out the checkout URL first, and
2060.173 -> also like, you know, the portal URL, and just
2062.435 -> have that saved as a hook or something like
2064.599 -> that before you actually press the button.
2066.665 -> So that's a way to make it faster.
2068.033 -> But anyways, when you click it, you should see it
2070.475 -> take you to this subscription page, this portal page,
2073.063 -> and you can see the product we bought here.
2075.213 -> And you can cancel the plan as well, or you can just go back to the store.
2078.96 -> So all of your details are here, you can update or add payment methods.
2082.843 -> So this is how your users can manage their payments to your website.
2086.72 -> And that's pretty much done.
2088.353 -> Let's recap again, what we've just built.
2090.565 -> So let's click out sign out here, we have a simple
2093.32 -> web app interface that has login integrated
2095.698 -> with Google that we implemented using Firebase.
2098.238 -> So we can see our authentication back-end here.
2101.021 -> And we can enable more things if we want to.
2103.255 -> But I just chose Google as the authentication provider.
2105.897 -> And when a user signs up here, it will be connected to your Stripe account as well.
2109.555 -> So you click here, a user can log in with a Google and
2112.518 -> users can be a premium member or a standard member.
2115.266 -> And then if they're a premium member, they can click here to manage
2118.78 -> the subscription and they'll take you to the Stripe page.
2121.726 -> Otherwise, if they're a standard member, they can click
2124.85 -> to buy the product and enter their credit card details.
2127.92 -> And all of the code for this project is on my GitHub,
2130.814 -> which I'm going to link in the description below.
2133.546 -> So "stripe-firebase-app".
2134.88 -> I hope you enjoyed this project.
2136.241 -> If you want to work on more things like this,
2138.222 -> then please subscribe to my channel so you
2140.159 -> get notified when I put out new content.
2141.92 -> And if you have any ideas, feel free to let me know in the comments.
2145.32 -> Otherwise, I hope you found this useful and thank you for watching.

Source: https://www.youtube.com/watch?v=xi3F2Zv91UE