Bad request in discord oauth

I’m creating a Discord login, but when I get redirected, I get the error. The error happens after I press authorize on the Discord OAuth page {"status":"ERROR","error":"Response code 400 (Bad Request)"} Here is my code for Discord.js

const express = require('express');

const router = express.Router();
const fetch = require('got');
const btoa = require('btoa');
const { catchAsync } = require('../utils');

const CLIENT_ID = '#';
const CLIENT_SECRET = '#';
const redirect = encodeURIComponent('https://ezapplications.live/api/discord/callback');

router.get('/callback', catchAsync(async (req, res) => {
  if (!req.query.code) throw new Error('NoCodeProvided');
const response = await fetch(`https://discordapp.com/api/oauth2/authorize?client_id=${CLIENT_ID}&scope=identify&response_type=code&redirect_uri=${redirect}`, {
  method: 'POST',
  body: new URLSearchParams({
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    grant_type: "authorization_code",
    redirect_uri: "https://ezapplications.live/api/discord/callback",
    code: req.query.code
  })
});
  const json = await response.json();
  res.redirect(`/?token=${json.access_token}`);
}));

router.get('/login', (req, res) => {
  res.redirect(`https://discordapp.com/api/oauth2/authorize?client_id=${CLIENT_ID}&scope=identify&response_type=code&redirect_uri=${redirect}`);
});

module.exports = router;

Here is my code for Server.js

const express = require('express');
const path = require('path');

const app = express();

app.get('/', (req, res) => {
  res.status(200).sendFile(path.join(__dirname, 'index.html'));
});
app.use('/api/discord', require('./api/discord'));

app.use((err, req, res, next) => {
  switch (err.message) {
    case 'NoCodeProvided':
      return res.status(400).send({
        status: 'ERROR',
        error: err.message,
      });
    default:
      return res.status(500).send({
        status: 'ERROR',
        error: err.message,
      });
  }
});

app.listen(50451, () => {
  console.info('Running on port 50451');
});

Here is the code for utils.js

// async/await error catcher
const catchAsyncErrors = fn => (
  (req, res, next) => {
    const routePromise = fn(req, res, next);
    if (routePromise.catch) {
      routePromise.catch(err => next(err));
    }
  }
);

exports.catchAsync = catchAsyncErrors;

I’m not sure why I get this error as everything seems fine to me, thanks.

Answer

As per the Authorization Code Grant docs, you need to pass the parameters in the request body instead of the query string.

const response = await fetch("https://discord.com/api/oauth2/token", {
  method: 'POST',
  headers: {
    "content-type": "application/x-www-form-urlencoded"
  },
  body: new URLSearchParams({
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    grant_type: "authorization_code",
    redirect_uri: "https://ezapplications.live/api/discord/callback",
    code: req.query.code
  }).toString()
});

Regarding HTTP Basic auth…

You can also pass your client_id and client_secret as basic authentication with client_id as the username and client_secret as the password

…but I don’t really see the point. Your choice