error: 'unsupported_grant_type', (durng token exchange)

I am attempting to do token exchange with an auth code, from an Express.js API. I am getting back an error object:

error: 'unsupported_grant_type',
  error_description: 'The supported grant types are `authorization_code` and `refresh_token`.'

This is the object I send as the post request body (stringified). Is there a mistake or omission somewhere?

tokenRequestBody {
  grant_type: 'authorization_code',
  client_id: '11885REMOVED',
  client_secret: 'b2d0b11a1REMOVED',
  redirect_uri: 'https://asanarepeater.ngrok.io/authCode',
  code: '1/111920289783REMOVED'
}

Here is the surrounding context:

router.get('/authCode', async (req: Request, res: Response) => {
  const tokenExchangeEndpoint = 'https://app.asana.com/-/oauth_token';

  const tokenRequestBody: IAuthCodeRequest = {
    grant_type: 'authorization_code',
    client_id: process.env.ASANA_CLIENT_ID!,
    client_secret: process.env.ASANA_CLIENT_SECRET!,
    redirect_uri: process.env.ASANA_HTTPS_REDIRECT_URL!,
    code: req.query.code as string,
  };

  // the object shown above
  console.log('tokenRequestBody', tokenRequestBody);

  try {
    const response = await fetch(tokenExchangeEndpoint, {
      method: 'post',
      // mode: 'cors',
      headers: {
        'content-type': 'application/json',
      },
      body: JSON.stringify(tokenRequestBody),
    });

    const tokenObject: ITokenResponseBody = await response.json();

    // the error object prints
    console.log('tokenObject', tokenObject);