In this guide I will show you how to bundle your SvelteKit app with Discord OAuth that’s handled on the server side of your web application.
You should be familiar with the basic concepts of SvelteKit and Discord to get most out of this guide. If you are looking for a quick start template, you can use my discord-oauth-starter template that has same project structure than this guide offers.
Looking for an Sapper alternative? Check out my Sapper version of this guide here.
Creating a new SvelteKit project
To get started, we will need to create a new SvelteKit project:
npm init svelte@next
When prompted about template to use, select Skeleton project with no Typescript. After that, please run npm install in order to install all the dependencies bundled with SvelteKit.
We will also need to install cookie node module to work with cookies in an easier way. You can do that by running:
npm install cookie
Creating a Discord application
Once we have the dependencies installed, we will need an Discord application. Let’s head over to Discord Developers Portal > Applications and create a new application.
What we need to grab is Client ID and Secret Token:
Now, we must also add OAuth2 Redirect URI by heading to applications OAuth2 tab:
Once we have everything fetched, let’s set up those details on environmental variables as referred in this guide:
- Start by creating .env file in your project root.
- Set it’s content to following:
VITE_DISCORD_API_URL="https://discordapp.com/api"
VITE_DISCORD_CLIENT_ID="YOUR-CLIENT-ID"
VITE_DISCORD_CLIENT_SECRET="YOUR-CLIENT-SECRET"
VITE_DISCORD_REDIRECT_URI="http://localhost:3000/api/callback"
VITE_HOST="http://localhost:3000"
Creating A Discord Authentication API
Now we can start building the authentication API in our app. Let’s add a new folder called api under src/routes folder. Within the api folder, we want to create auth.js route, callback.js route, refresh.js route and signout.js route.
routes/api/auth.js
Let’s start building those files from top to bottom, so starting from auth.js as it’s the simplest one to do.
When user visits your app’s api/auth path, they get redirected to Discord’s endpoint which then redirects the user back to our app.
Now if you run up your application with:
npm run dev -- --open
And head over to http://localhost:3000/api/auth route, it should redirect you to Discord’s authentication service. This is what you should see:
routes/api/callback.js
Callback.js route is the return URL where Discord’s authentication service brings our user back to. The full path is http://localhost:3000/api/callback.
The return URL will also contain the user’s return code, i.e. http://localhost:3000/api/callback?code=123456790123123
This return code is important because we can use it to fetch the actual access token for the user. Access token allows our application to perform certain actions for the authenticated user.
In a case where the return code is missing or is invalid, the user should be returned to front page of our application. On the other hand, if return token is valid then we store users access and refresh tokens in cookies and redirect the user to front page.
Here is the code breakdown for callback.js route:
routes/api/refresh.js
This route will handle refreshing the access token of user. This whole refresh process is greatly explained in a video b y Ben Awad. You can see it below, or skip it depending on your preference. Understanding the process is not required, but valuable.
Shortly put, each time our user connects to the application, we will get valid access token from Discord by using the refresh token. Then we will store the new tokens in cookies, or clear the cookies if fetching new token failed. Our access token will expire in 10 minutes from cookies, and refresh token in 30 days. Here is the code breakdown. It’s quite similar to callback one, but with slight difference especially in Discord endpoint:
routes/api/signout.js
Let’s add a sign out feature so user can clear their session, which is achieved by just clearing the cookies:
Reading user token on session
We obviously want to access the authenticated user from our application. To achieve this, we will need to verify on each session if they are authenticated or not.
First we should create a new file under src folder called hooks.js. If you don’t know what a hook is, refer to SvelteKit documentation.
After that, we are going to write a getSession() function which sends over our Discord user to the client (if authenticated).
Here is the code sample for that:
Accessing the Discord user object in Svelte layouts
Now the client has access to the Discord user object. To verify everything works, let’s do some modifications to index.svelte to load a Discord profile card if an user exists.
This can be achieved by using the load() function provided by SvelteKit, and fetching session.user from that.
Code sample for displaying basic details about user:
Here is what logged in user should see now on front-page:
Here is what non-logged users would see:
Let’s recap what we have built:
- Each time an user goes to /api/auth path, they are taken to Discord’s authentication service.
- After authenticating, Discord auth service returns the user to /api/callback which then returns the user to front-page with Discord tokens set in cookies.
- User access token is saved in cookies for 10 minutes and refresh token is for 30 days. If access token expires, we use refresh token to fetch new access token.
- Discord user object can be accessed via session object during loading of a page via session.user
- User can clear their session by going to /api/signout or clicking the sign out button on front-page.
That’s it, thanks for hopping by! We now have a barebones Discord OAuth2 web application done.
Consider checking out my sveltekit-discord-oauth-starter template to quickly develop Discord portals in the future.