How to Authorize a User With Discord OAuth

When building an app you may want to add different types of authentication. For example, you may want to allow users to sign up with their email address, or you may want to allow users to sign up with their Google account. In this article, we'll look at how to add Discord OAuth to your app.

Registering Our App

We'll be using Discord's OAuth2 API to authenticate users. To get started, we'll need to register an app with Discord. We can do this by visiting the Discord Developer Portal and clicking the “New Application” button.

Once we've created your app, we'll need to add a redirect URI. This is the URL that users will be redirected to after they've authenticated with Discord. We can add a redirect URI by clicking the “OAuth2” tab on the left-hand side of the screen, and then clicking the “Add Redirect” button.

We'll need to add a redirect URI for each environment that we're using. For example, if you're using a development environment, you'll need to add a redirect URI for that environment. In this article, we'll be using a development environment, so we'll add a redirect URI for that environment. Which will be http://localhost:3000/auth/discord/callback.

Creating Our Project

We'll be using Remix to build our app. If you're not familiar with Remix, you can learn more about it in our Getting Started with Remix article.

We'll start by creating a new Remix project. We can do this by running the following command:

npx create-remix@latest

We'll be using the create-remix command to create our project. This command will ask us a few questions about our project. We'll answer these questions as follows:

? Where would you like to create your app? ./discord-oauth2-tutorial
? What type of app do you want to create? Just the basics
? Where do you want to deploy? Vercel
? TypeScript or JavaScript? JavaScript
? Do you want me to run `npm install`? (Y/n) y

We can then cd into our project and start the development server by running the following commands:

cd discord-oauth2-tutorial
npm run dev

We'll now be able to visit our app at http://localhost:3000.

Basic Setup and Configuration

NOTE: We're using tailwindcss to style our app. If you want to learn how to use tailwindcss with Remix, you can read their guide here.

Next, we'll go into the routes folder and create a new folder called auth. We'll then create a new file inside the auth folder called discord.callback.jsx

Your routes folder should now look like this:

.
└── routes/
    ├── index.jsx
    └── auth/
        └── discord.callback.jsx

Next we'll remove the default code from index.jsx and replace it with the following code:

export default function Index() {
  return (
    <div className="flex h-full items-center justify-center bg-gray-900">
      <a className="rounded-md bg-indigo-600 px-4 py-2 text-xl text-white hover:cursor-pointer">
        Login
      </a>
    </div>
  )
}

And finally, we'll create a new file called .env in the root of our project. We'll then add the following code to the .env file:

DISCORD_CLIENT_ID=YOUR_CLIENT_ID
DISCORD_CLIENT_SECRET=YOUR_CLIENT_SECRET
DISCORD_REDIRECT_URI=http://localhost:3000/auth/discord/callback

We'll need to replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with the client ID and client secret that we got from Discord. We can find these values by visiting the Discord Developer Portal and clicking the “OAuth2” tab on the left-hand side of the screen.

NOTE: You'll need to restart the development server once you have added your environment variables.

Authorizing Users

Now we can start authorizing users. We'll start by adding our authorization link to our login page. We can do this by going to the Discord Developer Portal and clicking the “OAuth2” tab on the left-hand side of the screen. Then "URL Generator" button.

We'll then need to select the scopes that we want to use. In this article, we'll be using the identify scope. We can then copy the URL that's generated.

We'll then add this URL to our login page. We can do this by replacing the href attribute on our login link with the URL that we copied from the Discord Developer Portal.

export default function Index() {
  return (
    <div className="flex h-full items-center justify-center bg-gray-900">
      <a
        className="rounded-md bg-indigo-600 px-4 py-2 text-xl text-white hover:cursor-pointer"
        href="https://discord.com/api/oauth2/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fdiscord%2Fcallback&response_type=code&scope=identify"
      >
        Login
      </a>
    </div>
  )
}

Now when we click the login button, we'll be redirected to Discord's authorization page. We'll then need to click the “Authorize” button to authorize our app.

Once we've authorized our app, we'll be redirected to our redirect URI. We'll then need to extract the code from the URL and use it to get an access token. We can do this in our discord.callback.jsx file.

import { json } from '@remix-run/node'

export const loader = async ({ request }) => {
  // Get the code from the query string
  const url = new URL(request.url)
  const code = url.searchParams.get('code')

  // If we don't have a code, authorization failed
  if (!code) {
    return json({
      status: 400,
      error: 'An error occured while authorizing. Please try again.',
    })
  }

  // Exchange the code for an access token
  const response = await fetch('https://discord.com/api/v10/oauth2/token', {
    method: 'POST',
    body: new URLSearchParams({
      client_id: process.env.DISCORD_CLIENT_ID,
      client_secret: process.env.DISCORD_CLIENT_SECRET,
      code,
      grant_type: 'authorization_code',
      redirect_uri: process.env.DISCORD_REDIRECT_URI,
    }).toString(),
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
  })
  const credentials = await response.json()

  return json(credentials)
}

We do a few things in this file:

  1. We get the code from the query string
  2. We exchange the code for an access token using Discord's OAuth2 API
  3. We return the access token

We can now test our app by pressing the login button and authorizing our app. We should then be redirected to our redirect URI and see the access token in the browser.

If saving the tokens I would recommend encrypting them with a key that is stored in a database or something similar. This is out of scope for this article.

And thats it! We've now successfully authorized users with Discord. In the next article, we'll be using the access token to get information about the user.