Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

How To Manage Access and Refresh Tokens for an API in Next.js 13 With Supabase and Prisma

Posted on Sep 22 This article will show you how to use the Trackmania API in a Next.js 13 app using TypeScript. The API uses access and refresh tokens, so it is not as easily accessible as other APIs, like jsonplaceholder , or an API where you can include the same key(s) with every Request.So, we will use Supabase as a Postgres database to store the tokens and Prisma as our ORM of choice to communicate with our database.The main focus of this article is to show you how to store / retrieve these tokens for API use, NOT for user authentication. If you’re looking for user authentication, I’d recommend looking at an example here over on NextAuth’s website to get you started.If you’re still interested, let’s get started!Quickly download and setup the latest Next.js TypeScript starter:If you are getting warnings in your CSS file complaining about unknown CSS rules, follow these steps hereStill in globals.css, update the code with this reset from Josh ComeauUpdate tsconfig.json to this:Update src/app/page.tsx to this:Update src/app/layout.tsx to this:I’m a fan of setting up a GitHub repo and deploying to Vercel early, and committing + pushing often in smaller chunksThis way, if the site should not build on Vercel, it’s a lot easier to figure when the issue started occurring.I’m going to assume that since you’re doing this advanced tutorial that you:Please do both of these things before continuing.In order to use Nadeo’s Trackmania API, we need to get an access_token (which also comes with a refresh_token)There are 2 approaches to get this:While it is true that to login to trackmania.com, you need a Ubisoft account anyways, the flow for refreshing the access_token is much simpler using a Server Account.On trackmania.com, once you are signed in, click on your user name in the top right cornerIn the dropdown, select My Server AccountsEnter a value for the Server Login (you can think of this is a project name)I’ll call mine: trackmania-api-demoClick SubmitOnce you do, a message will appear to Please copy the passwordCopy the Login (the name you just entered, ie trackmania-api-demo) and password into a text file for nowLet’s use Postman (or a similar platform of your choice) to send requests first to make sure things will work before coding it all up.Create a new request with the following:Under BodyClick Send, and you should see a response like this:The start of the access_tokens, known as the HEADER, is always the same, so it’s safe to display them publicly like this. However, it’s the PAYLOAD and SIGNATURE parts of the tokens that are unique.If you URL-base64-decode the PAYLOAD part of the accessToken, you get the following JSON object:Here, exp defines the expiration time, and rat defines the time after which you are able to refresh the token.To URL-base64-decode something in TypeScript, you can use a function like this:To keep things simple, let’s try and fetch the data for a single map for now to make sure our access_token is workingLet’s fetch data for the first map in the current campaign (which at the time of writing, is Summer 2023-01)We will need send a GET request to the following URL:To get a MAP_UID, head back to the official Trackmania site: https://www.trackmania.com/Once there, click on CampaignsThen click SUMMER 2023 - 01 on the next pageThe URL will be this: https://www.trackmania.com/tracks/7hk8IflYsbMbpJv2gyYzx48Zvt7The last part in the path, 7hk8IflYsbMbpJv2gyYzx48Zvt7, is the MAP_UIDBack in Postman, create another request tab and set the following:Under BodyClick Send, and you should see a response like this:Hazah! If you’ve made it this far, congrats! This is a very good milestone to hit.Ok, so now that we’ve tested some queries in Postman to ensure we get the responses we want, we should pause here and plan out how we want to do code wise:Most resources online I’ve seen suggest using a JWT to store the refresh_token. However, using a JWT to store the refresh_token is less secure than saving it in a database.Instead, we will use Supabase to store our tokens, and use Prisma as our ORM of choice to read and write data to / from the database.First, let’s install Prisma as a devDependencyNext, we can initialize Prisma by running:This will create an .env file as well as a prisma folder, both at the root levelNOTES:Create an account if you do not have one alreadyOnce logged in, go to your DashboardOn the dashboard page, click New projectGive it a name, something in kebal-case-like-thisClick generate a passwordCopy and paste the generated password into the .env file as a comment for nowChange your region accordinglyClick Create new projectNavigate to the project settings (gear icon, very bottom of sidebar nav)Click on DatabaseUnder Connection string, click URICopy this valueBack in the .env file, replace the default DATABASE_URL with the URI you just copied.Also update the [YOUR-PASSWORD] placeholder with the generated password from before.Back in Supabase, click on the Database icon.Under tables, there should be nothing there. But not for long!Open the schema.prisma file generated earlierWe’ll add a simple ApiToken model:This will be sufficient because we are not performing any auth, we are simply saving the keys in a secure location for when we want to reach out to the Trackmania APIWhile we’re at it, let’s also update the .env file with Trackmania Server Account login and password from earlier:We’ll need these whenever we make the initial POST request to get the tokensNow we need to migrateRun this command:Go back to Supabase, and click on the Table Editor iconYou should now see a User table!Link to Prisma Client docs hereInstall it:Next, inside the src folder, create a folder called libIn the lib folder, create a file called prisma.tsThere are some common / well known issues when working with Next.js and PrismaThere is a docs page about it hereCopy and paste this snippet (taken from the docs) into prisma.ts:What this code does is when we are not in the production environment, and the Prisma client has already run, the PrismaClient won’t be initialized again and again every time we restart the server.At this point, it’s a good idea to update our Environment Variables on Vercel with the values we’ve added.From your dashboard, select the project you’ve created / deployed.Click on Settings, then Environment Variables.Add them here (you can actually copy / paste multiple at a time!).Head over to Supabase, and enter in a row manually.Perform a POST request in Postman to get an up-to-date access and refresh tokenYou can then use the urlBase64Decode function shown earlier to get the exp valueYou can then use this function to create a Date string from that value:Use this value for the expirationDateFor the tokenId, you can also use this generateCUID function in a browser console to generate an id for you (thanks ChatGPT!):Since we need to always be checking whether or not the access_token is valid or not, we need some code to run on every pageA simple way to implement this is by using middlewareInside the src directory, create a file called middleware.tsAdd this code to it for now:Then if you run npm run dev, you should see the console.log when you visit / refresh the home page.Next, let’s update this code to fetch the example row from Supabase we added earlier:However, when we do this, we will get this error:At the time of writing, as the error says, PrismaClient is unable to run in Vercel Edge Functions.Thankfully, it is being discussed and it looks like a solution is being worked on.To get around this, we can use Prisma DataProxy.To start, head over to https://cloud.prisma.io/ and create an account with your GitHub login.Once you’ve authorized Prisma, go to your projects dashboard here (you also might automatically be directed to the create a project flow).Click on Create classic project.Copy and paste your DATABASE_URL from the .env file into the Connection string field.Click Create project.Add your GitHub profile if not selectable.Select your repo, and make sure the branch is set to main.Create a Data Proxy connection string, give it a name.Copy the value, and head back to the code and open the .env file.Rename the existing DATABASE_URL variable to MIGRATE_DATABASE_URL.Then create a DATABASE_URL, this time setting it to the proxy connection string you just created.The MIGRATE_DATABASE_URL will be used to apply and pending migration to the database as the app will be deployed on Vercel.Next, open up the terminal and run:This will generate a Prisma client that will use Prisma data proxyNext, go to prisma.ts and adjust the import path of the PrismaClientlike so:After that, run npm run dev in the terminal, and you should now see the response:We should update the ApiToken model to also have a addedOn fieldThis will help us get the row in the database that was added most recentlyWe will also need to add a directUrl property to the datasource db:Again, the MIGRATE_DATABASE_URL is the old DATABASE_URL that was copied from Supabase.Make sure to also add / update your Environment Variables on Vercel too!Now we can run migrate command:If you didn’t specify the directUrl, you would get an error. So that is why we added it.Link to the docs page about using Prisma Migrate hereFinally, we will need to add this script to our package.json (as per Prisma docs here):We do this because you would run into the following error message on deployment otherwise:So now we can begin writing the necessary code to check our tokens in the databaseBut first, let’s setup a simple request on the home page knowing it will fail:As you can see, we are missing the Authorization along with the accessToken. This is where middleware can help us.We can use it to set headers on requests. We will use it to set the access_token on each request to the Trackmania API. In the end, it looks like this:That’s quite a lot! Let’s break it down:If it is, that means the access_token is expired and we need to get a new oneAnd outside this expiration check, we set new a Authorization header using the most recent access tokenWhew!Now we can go back to the home page and adjust our query:Here, we leverage the added on headers using the headers function from next/headers. It is read only, but that is perfectly fine since we just want to include it with our request anyways. If you don’t include this, the request fails.Here is what the TrackmaniaTrack type looks like:And now, if you check the terminal, you should get the correct response, as well as the map name should appear on the screen!One thing I noticed was that sometimes the site errors out instead of using the most recent access_token. The solution is to simply refresh the page. So, as a temporary fix, I’ve created some basic back up pages:I also created a root level loading.tsx so something is shown while the site is loading, which provides a better UX:I cannot stress how helpful the documentation over on Openplanet was in building this app. Big thanks to them! You can also view a list of the most common endpoints here.And that’s it! As stated in the beginning, this was mainly to demonstrate how to use Supabase to store and retrieve tokens in a secure fashion instead of using JWT for API use. Most resources I found were revolving around authorization / user accounts, not using just an API. And I wanted to push myself and reinforce what I’ve been learning lately, and I’m very proud of myself for figuring this out.The next steps are, well, up to you! If you want to continue building out your own Trackmania web app, you now have the proper foundation to do so. If not, you have the knowledge for storing tokens if the API you are using has a similar setup.You could perhaps display maps from the current season on the home page, and create dynamic routes to each of them. Then, on an individual map page, display some information about that map.The next major feature would be to include NextAuth using Ubisoft as a custom provider. Buuuttt I’m gonna leave that for another day ;)I hope you found this article helpful. As always, you can view the full source here in case you get stuck.If you have any feedback for me on how I could improve the code, please let me know! This was only the second time I’ve built a project using this stack, so any suggestions you may have are greatly appreciated!Cheers, and happy coding!Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well Confirm For further actions, you may consider blocking this person and/or reporting abuse Code Reliant - Sep 3 ryad - Sep 7 Nikola Cosic - Sep 7 Achmad Fauzian Dhany Hidayat - Sep 7 Once suspended, andrews1022 will not be able to comment or publish posts until their suspension is removed. Once unsuspended, andrews1022 will be able to comment and publish posts again. Once unpublished, all posts by andrews1022 will become hidden and only accessible to themselves. If andrews1022 is not suspended, they can still re-publish their posts from their dashboard. Note: Once unpublished, this post will become invisible to the public and only accessible to Andrew Shearer. They can still re-publish the post if they are not suspended. Thanks for keeping DEV Community safe. Here is what you can do to flag andrews1022: andrews1022 consistently posts content that violates DEV Community's code of conduct because it is harassing, offensive or spammy. Unflagging andrews1022 will restore default visibility to their posts. DEV Community — A constructive and inclusive social network for software developers. With you every step of your journey. Built on Forem — the open source software that powers DEV and other inclusive communities.Made with love and Ruby on Rails. DEV Community © 2016 - 2023. We're a place where coders share, stay up-to-date and grow their careers.



This post first appeared on VedVyas Articles, please read the originial post: here

Share the post

How To Manage Access and Refresh Tokens for an API in Next.js 13 With Supabase and Prisma

×

Subscribe to Vedvyas Articles

Get updates delivered right to your inbox!

Thank you for your subscription

×