I’m currently trying to build a little Slack app. The (Botkit based) app is a “slash command” that also needs access to the team and user info Slack web API methods.
I ran into a problem where I needed an access token that Botkit stores in its users object store. The issue is that when I need to use the access token to call the Slack web API methods, I need to find that token. I wanted to lookup that access token via the team_id that is passed in through the slash command message, but I couldn’t if the token is in the users object store, with the install user’s ID as the key.
Here is an example of what I had in the Botkit users and teams object stores after a user installed my app:
botkit:store:teams
{"id":"T1DDTABCD","createdBy":"U1DDKABCD","url":"https://someslackteam.slack.com/","name":"slack-team-name"}
botkit:store:users
{"id":"U1DDKABCD","access_token":"xoxp-49999999999-49999999999-59999999999-7e05d2266c","scopes":["identify","commands"],"team_id":"T1DDTABCD","user":"johndoe"}
When my app gets a message, it doesn’t have access to the install user’s ID, but it does have the team ID. I needed to pass in that “access_token” for the web API calls like this:
var token = ''; //Need the access token
var options = {
user: message.user,
token: token
}
bot.api.users.info(options, function (err, response) {
var user = response.user;
var username = user.name;
});
My workaround was to get the access_token from the install user during the install process and store it with the team. This is what that code looks like:
controller.setupWebserver(process.env.PORT, function(err, webserver) {
controller.createWebhookEndpoints(controller.webserver);
// Used for app install url/login
controller.createOauthEndpoints(controller.webserver, function(err, req, res) {
if (err) {
res.status(500).send('ERROR: ' + err);
} else {
// Need to store the user access_token with the team for easy access later
var teamID = req.identity.team_id;
var userID = req.identity.user_id;
controller.storage.users.get(userID, function(err, user) {
var token = user.access_token;
if (err) {
console.error('users get err: ' + err);
}
controller.storage.teams.get(teamID, function (err, team) {
if (err) {
console.error('teams get error: ' + err);
}
team.access_token = token;
controller.storage.teams.save(team, function(err) {
if (err) {
console.error('teams save err: ' + err);
}
});
});
});
res.send(templates.appInstallSuccess);
}
});
});
That happens once during install and adds the access token to the teams record:
botkit:store:teams
{"id":"T1DDTABCD","createdBy":"U1DDKABCD","url":"https://someslackteam.slack.com/","name":"slack-team-name", "access_token":"xoxp-49999999999-49999999999-59999999999-7e05d2266c"}
botkit:store:users
{"id":"U1DDKABCD","access_token":"xoxp-49999999999-49999999999-59999999999-7e05d2266c","scopes":["identify","commands"],"team_id":"T1DDTABCD","user":"johndoe"}
I could then call the Slack web API like this:
controller.storage.teams.get(message.team_id, function(err, team) {
var token = team.access_token;
var options = {
user: message.user,
token: token
}
// Call users.info Slack web API to look up user info
bot.api.users.info(options, function (err, response) {
var user = response.user;
var username = user.name;
});
Notice I’m calling the teams storage and passing in the message.team_id to look up the team for the user who submitted the command.