Missing or unknown auth code

Hi, I know there are some posts about the “missing or unknown auth code” error in the forum but I feel like I’m missing the solution here.

require('dotenv').config();
const express = require('express');
const request = require('request-promise-native');
const NodeCache = require('node-cache');
const session = require('express-session');
const opn = require('open');
const app = express();

const PORT = 3000;

const refreshTokenStore = {};
const accessTokenCache = new NodeCache({deleteOnExpire: true});

if (!process.env.CLIENT_ID || !process.env.CLIENT_SECRET) {
 throw new Error('Missing CLIENT_ID or CLIENT_SECRET environment variable.')
}

//===========================================================================//
// HUBSPOT APP CONFIGURATION
//===========================================================================//

const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;

let SCOPES = ['crm.objects.contacts.read', 'crm.objects.contacts.write', 'forms'];
if (process.env.SCOPE) {
 SCOPES = process.env.SCOPE.split(/ |, ?|%20/).join(' ');
}

const REDIRECT_URI = `http://localhost:${PORT}/oauth-callback`;

//===========================================================================//

app.use(session({
 secret: Math.random().toString(36).substring(2),
 resave: false,
 saveUninitialized: true
}));

const authUrl =
 'https://app-eu1.hubspot.com/oauth/authorize' +
 `?client_id=${encodeURIComponent(CLIENT_ID)}` +
 `&scope=${encodeURIComponent(SCOPES)}` +
 `&redirect_uri=${encodeURIComponent(REDIRECT_URI)}`;

console.log("authurl url => ", authUrl);

//================================//
// OAuth 2.0 Flow //
//================================//

app.get('/install', (req, res) => {
 console.log('\n=== Initiating OAuth 2.0 flow with HubSpot ===\n');
 console.log("===> Step 1: Redirecting user to your app's OAuth URL");
 res.redirect(authUrl);
 console.log('===> Step 2: User is being prompted for consent by HubSpot');
});

app.get('/oauth-callback', async (req, res) => {
 console.log('===> Step 3: Handling the request sent by the server');

 if (req.query.code) {
 console.log(' > Received an authorization token --> ', req.query.code);

 const authCodeProof = {
 grant_type: 'authorization_code',
 client_id: CLIENT_ID,
 client_secret: CLIENT_SECRET,
 redirect_uri: REDIRECT_URI,
 code: req.query.code
 };

 console.log('===> Step 4: Exchanging authorization code for an access token and refresh token');

 try {
 const token = await exchangeForTokens(req.sessionID, authCodeProof);
 if (token.message) {
 return res.redirect(`/error?msg=${token.message}`);
 }

 res.redirect(`/`);
 } catch (error) {
 console.error('Error exchanging authorization code for access token:', error);
 res.redirect(`/error?msg=Error exchanging authorization code`);
 }
 } else {
 console.error('Authorization code missing');
 res.redirect('/error?msg=Authorization code missing');
 }
});

app.get('/', async (req, res) => {
 res.setHeader('Content-Type', 'text/html');
 res.write(`<h2>HubSpot OAuth 2.0 Quickstart App</h2>`);
 if (isAuthorized(req.sessionID)) {
 const accessToken = await getAccessToken(req.sessionID);
 const contact = await getContact(accessToken);
 res.write(`<h4>Access token: ${accessToken}</h4>`);
 displayContactName(res, contact);
 } else {
 res.write(`<a href="/install"><h3>Install the app</h3></a>`);
 }
 res.end();
});

app.get('/error', (req, res) => {
 res.setHeader('Content-Type', 'text/html');
 res.write(`<h4>Error: ${req.query.msg}</h4>`);
 res.end();
});

app.listen(PORT, () => console.log(`=== Starting your app on http://localhost:${PORT} ===`));
opn(`http://localhost:${PORT}`);

//===========================================================================//
// Functions Definitions //
//===========================================================================//

const exchangeForTokens = async (userId, exchangeProof) => {
 try {
 const data = {
 url: 'https://api.hubapi.com/oauth/v1/token',
 form: exchangeProof,
 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
 };
 const responseBody = await request.post('https://api.hubapi.com/oauth/v1/token', data)
 console.log("exchange post responsebody:", responseBody);

 const tokens = JSON.parse(responseBody);
 refreshTokenStore[userId] = tokens.refresh_token;
 accessTokenCache.set(userId, tokens.access_token, Math.round(tokens.expires_in * 0.75));

 console.log(' > Received an access token and refresh token');
 return tokens.access_token;
 } catch (e) {
 console.error(` > Error exchanging ${exchangeProof.grant_type} for access token`);
 console.error(e.response.body);
 return JSON.parse(e.response.body);
 }
 }
;

const refreshAccessToken = async (userId) => {
 const refreshTokenProof = {
 grant_type: 'refresh_token', client_id: CLIENT_ID, client_secret: CLIENT_SECRET, redirect_uri: REDIRECT_URI, refresh_token: refreshTokenStore[userId]
 };
 return await exchangeForTokens(userId, refreshTokenProof);
};

const getAccessToken = async (userId) => {
 if (!accessTokenCache.get(userId)) {
 console.log('Refreshing expired access token');
 await refreshAccessToken(userId);
 }
 return accessTokenCache.get(userId);
};

const isAuthorized = (userId) => {
 return !!refreshTokenStore[userId];
};

const getContact = async (accessToken) => {
 console.log('\n=== Retrieving a contact from HubSpot using the access token ===');
 try {
 const headers = {
 Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json'
 };
 console.log('===> Replace the following request.get() to test other API calls');
 console.log('===> request.get(\'https://api.hubapi.com/contacts/v1/lists/all/contacts/all?count=1\')');
 const result = await request.get('https://api.hubapi.com/contacts/v1/lists/all/contacts/all?count=1', {
 headers: headers
 });

 return JSON.parse(result).contacts[0];
 } catch (e) {
 console.error(' > Unable to retrieve contact');
 return JSON.parse(e.response.body);
 }
};

const displayContactName = (res, contact) => {
 if (contact.status === 'error') {
 res.write(`<p>Unable to retrieve contact! Error Message: ${contact.message}</p>`);
 return;
 }
 const {firstname, lastname} = contact.properties;
 res.write(`<p>Contact name: ${firstname.value} ${lastname.value}</p>`);
};

{“status”:“BAD_AUTH_CODE”,“message”:“missing or unknown auth code”,“correlationId”:“abcd1234etc etc etc”}
Scratching my head here…

Hmmm, before you use the token you might try calling this endpoint to get the metadata for the token and that may tell you what is wrong with it. Accounts Dashboard | HubSpot /oauth/v1/access-tokens/{token}

It seems ok when i reach that endpoint + accessToken, I’m looking for a complete guide for the various use cases, can you suggest some document or video other than the standard documentation?

No I can’t offhand other than point you to the academy development courses. I assume you know about those.