Hi everyone,
I’m developing an integration app that includes an OAuth process. When the app is installed, two authorization processes are triggered via the authorization_url
:
- Collecting the 3rd-party API token from the user and saving it in secure storage using the account ID as the key (e.g.,
api_token_<account_id> -> <3rd_party_token>
). - Performing the OAuth2 process to request user authorization for the app’s scopes and saving the Monday API token in secure storage (e.g.,
monday_api_token_<account_id> -> <monday_token>
).
The issue arises in the second process (OAuth). I need the account_id
to store the user’s Monday token in secure storage. Unlike the first process, where the authorization_url
provides a JWT token to retrieve the account_id
, the second process doesn’t include a JWT token, leaving me without the account_id
.
How can I obtain the account_id
during the OAuth process?
Route that triggered once user install the app feature (authorization_url
) - collect the 3rd party token
app.get("/authorization", async (req, res) => {
// Get the token from the query parameter
const { token } = req.query;
try {
// Verify the JWT token
const { userId, accountId, backToUrl } = jwt.verify(token, process.env.MONDAY_SIGNING_SECRET);
// Render a form for the user to input the API token and secret
res.send(`
...
<form action="/submit-credentials" method="POST">
<input type="hidden" name="backToUrl" value="${backToUrl}}">
<input type="hidden" name="userId" value="${accountId}">
<label for="apiSecret">API Secret:</label>
<input type="password" id="apiSecret" name="apiSecret" required placeholder="Enter your API secret">
<label for="apiToken">API Token:</label>
<input type="text" id="apiToken" name="apiToken" required placeholder="Enter your API token">
<button type="submit">Submit</button>
</form>
`);
logger.info(`Sending authorization form to the user...`);
} catch (err) {
return res.status(400).send("Invalid token");
}
});
Route that triggered once the user submit the 3rd party credentials:
// POST /submit-credentials route to handle form submission
app.post("/submit-credentials", async (req, res) => {
// Get the token from the query parameter
const { apiToken, apiSecret, backToUrl, userId } = req.body;
try {
// Use unique keys based on the accountid
await secureStorage.set(`Token_${accountId}`, apiToken);
logger.info(`Stored the user credentials in the secure store for account id ${accountId}`);
return res.redirect(redirect_uri + "/start");
} catch (error) {
logger.error('Error storing credentials:', error);
return res.status(500).send('Failed to store credentials');
}
});
Route that triggered after saving the 3rd party credentials and start OAuth2:
app.get('/start', function (req, res) {
var state = '...'; // change this to a random string in your implementation
res.cookie('state', state);
res.redirect('https://auth.monday.com/oauth2/authorize?' +
querystring.stringify({
client_id: client_id,
redirect_uri: redirect_uri + '/oauth/callback',
state: state,
scopes: "boards:read boards:write"
}));
});
Route the triggered after the user authorize the scope of the app:
app.get('/oauth/callback', function (req, res) {
// upon callback, your app first checks state parameter
// if state is valid, we make a new request for access and refresh tokens
var code = req.query.code || null;
var state = req.query.state || null;
var storedState = req.cookies ? req.cookies['state'] : null;
if (state === null || state !== storedState) {
...
} else {
res.clearCookie('state');
var authRequest = {
url: 'https://auth.monday.com/oauth2/token',
form: {
redirect_uri: redirect_uri + '/oauth/callback',
client_id: client_id,
client_secret: client_secret,
code: code,
},
};
// POST auth.monday.com/oauth2/token
request.post(authRequest, function (error, response, body) {
if (!error && response.statusCode === 200) {
var jsonBody = JSON.parse(body);
var accessToken = jsonBody.access_token || null;
var refreshToken = jsonBody.refresh_token || null;
var tokenType = jsonBody.token_type || null;
var scope = jsonBody.scope || null;
!!! HERE I WOULD LIKE TO GET THE ACCOUNT_ID !!!
!!! HERE I WOULD LIKE TO SAVE THE TOKEN TO THE SECURE STORAGE WITH ACCOUNT_ID AS KEY !!!
res.redirect("/finish?" +
querystring.stringify({
status: 'success',
access_token: accessToken,
refresh_token: refreshToken,
token_type: tokenType,
scope: scope,
}));
} else {
...
}
});
}
});
I suppose I could pass the account ID from the submit_credentials
route to the /start
route and then store it in a cookie to pass it along. However, this feels a bit cumbersome. If you have a better solution, I’d love to hear it!
Thank you in advance for your help!