How do you receive access token for API request using OAuth and Node?

I am building a framework for a node.js app using Express and am having trouble with receiving my access_token. I successfully send the user to retrieve the authorization code, log in, and then select Authorize, but upon selecting Authorize the app logs a 400 Status Code and the browser shows "502 Bad Gateway /  The server returned an invalid or incomplete response." I am using ngrok to create a secure channel to localhost:3000 and have all of my Redirect URIs listed below. If you can point me in the right direction to fix this, that would be much appreciated.

Redirect URIs

Code

// index.js

const express = require('express');
const querystring = require('querystring');
const https = require('https');
const morgan = require('morgan');

const clientID = process.env.clientID;
const clientSecret = process.env.clientSecret;
const codeRedirect = encodeURI('https://ynag.ngrok.io/oauth/token');
const tokenRedirect = encodeURI('https://ynag.ngrok.io/app');

const app = express();
const port = process.env.PORT || 3000;

let authCode;

app.use(morgan('dev'));

// Home Route
app.get('/', (req, res) => {
  res.send('App Home');
});

// Obtain Authorization Code
app.get('/oauth/redirect', (req, res) => {

  res.redirect(`https://app.youneedabudget.com/oauth/authorize?client_id=${clientID}&redirect_uri=${codeRedirect}&response_type=code`);

});

// Obtain Access Token
app.get('/oauth/token', (req, res) => {
  authCode = req.query.code;
  console.log(`Client ID: ${clientID} \nClient Secret: ${clientSecret} \nAuthorization Code: ${authCode}`);

  let postData = querystring.stringify({
    'client_id': clientID,
    'client_secret': clientSecret,
    'redirect_uri': tokenRedirect,
    'grant_type': 'authorization_code',
    'code': authCode
  });

  let options = {
    hostname: 'app.youneedabudget.com',
    port: 443,
    path: '/oauth/token',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(postData)
    }
  };

  let post_req = https.request(options, (res) => {
    console.log(`STATUS: ${res.statusCode}`);
    console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
    res.setEncoding('utf8');
    res.on('data', (chunk) => {
      console.log(`BODY: ${chunk}`);
    });
    res.on('end', () => {
      console.log('No more data in response.');
    });
  });

  post_req.on('error', (e) => {
    console.error(`problem with request: ${e.message}`);
  });

  post_req.write(postData);
  post_req.end();

});

// Successful Login Route
app.get('/app', (req, res) => {
  res.send('Logged in.');
  console.log(res);
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}.`);
});
6replies Oldest first
  • Oldest first
  • Newest first
  • Active threads
  • Popular
  • Spring Green Major - This might be specific to ngrok.  I believe when a session expires it will return a 502 response.  Are you sure the ngrok endpoint is active and working?  Are you able to access your URL (i.e. https://ynag.ngrok.io) through a browser and pull up you locally running app?

    Like
      • Jared Blumer
      • Developer
      • jaredblumer
      • 9 mths ago
      • Reported - view

      Brady Thanks for your reply, Brady. The ngrok endpoint was active and working during testing. Do you recommend that I develop using a https localhost server without ngrok instead?

      Like
    • Jared Blumer Using ngrok with https should be fine.  I use it for local testing as well.

      You said:

      but upon selecting Authorize the app logs a 400 Status Code and the browser shows "502 Bad Gateway /  The server returned an invalid or incomplete response."

      When you click the "Authorize" button on https://app.youneedabudget.com/oauth/authorize(...) is it redirecting back to your ngrok URL? And is the error coming from that URL? Or, is the error showing on app.youneedabudget.com (our app)?

      Like
      • Jared Blumer
      • Developer
      • jaredblumer
      • 9 mths ago
      • Reported - view

      Brady Hi Brady, it redirects back correctly upon selecting Authorize (as verified by console logs that show that the authorization code has been sent as a query parameter), but I appear to be having a problem with the POST request that occurs after the redirect. I have the POST request embedded within my redirected GET route (/oauth/token), so I receive the redirect from clicking Authorize and then get the 400 error in my app's console log which appears to be your API rejecting my POST request. Then I believe your page times out due to not accepting my next redirect URL within the POST request.

      I believe I have this part of the app structured incorrectly. I tried it using the request npm module as well, rather than node's https module, and had the same issue, so it appears to be caused by my POST request directly or how I am structuring my application.

      Thanks again for your help.

      Like
    • Jared Blumer Oh!  It looks like you're passing the wrong "Content-Type" request header when posting to /oauth/token.  It looks like you are using form/urlencoded format so you'll need to specify it as "application/x-www-form-urlencoded".  

      Like this:

        let options = {
          hostname: 'app.youneedabudget.com',
          port: 443,
          path: '/oauth/token',
          method: 'POST',
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',   // < Change is here
            'Content-Length': Buffer.byteLength(postData)
          }
        };
      Like
      • Jared Blumer
      • Developer
      • jaredblumer
      • 9 mths ago
      • Reported - view

      Brady Awesome! I'll give that shot and get back to you when I do. Thanks, Brady!

      Like
Like Follow
  • 9 mths agoLast active
  • 6Replies
  • 138Views
  • 2 Following