Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to setup the oauth flow? #302

Closed
4 of 9 tasks
kroltan opened this issue Oct 28, 2019 · 12 comments
Closed
4 of 9 tasks

How to setup the oauth flow? #302

kroltan opened this issue Oct 28, 2019 · 12 comments
Labels
question M-T: User needs support to use the project

Comments

@kroltan
Copy link

kroltan commented Oct 28, 2019

Description

I've developed a bot and it works fine on its home workspace. Now I need to make oauth work so it can be installed on other workspaces. How can I do that? Does Bold provide anything by default?

What type of issue is this? (place an x in one of the [ ])

  • bug
  • enhancement (feature request)
  • question
  • documentation related
  • testing related
  • discussion

Requirements (place an x in each of the [ ])

  • I've read and understood the Contributing guidelines and have done my best effort to follow them.
  • I've read and agree to the Code of Conduct.
  • I've searched for any related issues and avoided creating a duplicate issue.
@seratch
Copy link
Member

seratch commented Oct 30, 2019

At the moment, Bolt doesn't have a feature to handle OAuth flow as a part of the framework. Bolt users need to implement https://api.slack.com/docs/oauth on their own.

After implementing the OAuth flow, only the thing to do is to implement the authorize function: https://slack.dev/bolt/concepts#authorization

@ErwinAI
Copy link

ErwinAI commented Oct 31, 2019

@kroltan To help you on your way, this is my boilerplate of the oauth flow, working alongside Bolt. It also uses the express instance of Bolt, rather than a new one. It might need some tweaks here and there, but it should be useful. Don't forget to implement the state mechanism though, it's very important.

Side note: it's not using oauth.v2.access method because it doesn't seem to be available in Bolt yet either.

const { App, ExpressReceiver } = require('@slack/bolt');
const expressReceiver = new ExpressReceiver({
    signingSecret: <signing secret>,
    endpoints: '/events'
});
//TODO: implement this function see Bolt documentation under "Authorization"
const app = new App({
    authorize: authorizeFn, 
    receiver: expressReceiver
});

const app_express = expressReceiver.app;

/* Page with add button, can be implemented in website instead */
app_express.get('/auth/add', (req, res, next) => {
    //TODO: fill in correct Embeddable slack button
    res.write('[ Slack API > your app > Manage Distribution > Embeddable slack button ]');
    res.end();
});
/* Support for Direct Install */
app_express.get('/auth/direct', (req, res, next) => {
    //TODO: fill in correct Sharable URL
    res.redirect('[ Slack API > your app > Manage Distribution > Sharable URL ]);
    res.end();
});

/* oauth callback function */
app_express.get('/auth/callback', (req, res, next) => {
    let code = req.param("code");

    // TODO: add state to your oauth url in /auth/add (button) and /auth/direct (direct install) and check it here to make sure there is no XSRF attack going on.
    let state = req.param("state");

    return app.client.oauth.access({
        client_id: <client_id>,
        client_secret: <client_secret>,
        code: code
    }).then(async (result) => {
        // save result of oauth.access call somewhere, like in a database.

        // redirect user afterwards with res.redirect to an url that will say something like "Thanks for installing!" perhaps.
    }).catch((error) => {
        throw error;
    });
});

@kroltan kroltan closed this as completed Nov 5, 2019
@aoberoi
Copy link
Contributor

aoberoi commented Nov 11, 2019

Folks who are still stuck on this, you might want to check out this project: https://github.com/asopinka/bolt-oauth

I haven't used it myself yet, but it seems to solve this problem in a reusable way.

@jacklein
Copy link

jacklein commented Dec 17, 2019

I have a question about:

const app = new App({
  authorize: authorizeFn, 
  receiver: expressReceiver
});

Does app get reinitialized every time a request comes in? Like when I deploy my bolt code to Heroku or whatever, and users from multiple slack teams hit the express endpoints, how does an app get properly initialized for all those teams? I think I'm just confused about the lifecycle of the node.js code?

The question is a bit naive but I'd appreciate any help 🙏

@aoberoi aoberoi reopened this Dec 17, 2019
@aoberoi aoberoi added the question M-T: User needs support to use the project label Dec 17, 2019
@seratch
Copy link
Member

seratch commented Dec 17, 2019

@jacklein

Does app get reinitialized every time a request comes in?

No, it doesn't.

how does an app get properly initialized for all those teams?

Every time App receives a request from Slack, App runs authorizeFn to check if the app is installed to the workspace. If the team_id (plus optionally enterprise_id) is absent in the app's database (the one authorizeFn checks), the request will be automatically denied by Bolt. Otherwise, the authorized data (botToken etc) will be given as part of context arg for listeners. Checking the framework code may be easier to understand the flow:
https://github.com/slackapi/bolt/blob/%40slack/bolt%401.4.1/src/App.ts#L385-L393

At the moment, Bolt doesn't offer the features to manage your database. So, as the examples above do, your app needs to insert/update/delete rows in the database when users install/uninstall your app.

Does this explanation make sense to you?

@jacklein
Copy link

jacklein commented Dec 17, 2019

@seratch ahhhhh authorizeFn gets called on every incoming request. That makes sense. One other quick question I have is if the workspace is not an enterprise workspace, will enterpriseId just be nil? In which case we will just search for the teamId in our db?

Thanks!!

Edit: I now see your comment about enterpriseId. This all makes sense, thank you again for all the help.

@seratch
Copy link
Member

seratch commented Dec 17, 2019

Happy to be of help to you! 😃

@sanju-27
Copy link

@kroltan To help you on your way, this is my boilerplate of the oauth flow, working alongside Bolt. It also uses the express instance of Bolt, rather than a new one. It might need some tweaks here and there, but it should be useful. Don't forget to implement the state mechanism though, it's very important.

Side note: it's not using oauth.v2.access method because it doesn't seem to be available in Bolt yet either.

const { App, ExpressReceiver } = require('@slack/bolt');
const expressReceiver = new ExpressReceiver({
    signingSecret: <signing secret>,
    endpoints: '/events'
});
//TODO: implement this function see Bolt documentation under "Authorization"
const app = new App({
    authorize: authorizeFn, 
    receiver: expressReceiver
});

const app_express = expressReceiver.app;

/* Page with add button, can be implemented in website instead */
app_express.get('/auth/add', (req, res, next) => {
    //TODO: fill in correct Embeddable slack button
    res.write('[ Slack API > your app > Manage Distribution > Embeddable slack button ]');
    res.end();
});
/* Support for Direct Install */
app_express.get('/auth/direct', (req, res, next) => {
    //TODO: fill in correct Sharable URL
    res.redirect('[ Slack API > your app > Manage Distribution > Sharable URL ]);
    res.end();
});

/* oauth callback function */
app_express.get('/auth/callback', (req, res, next) => {
    let code = req.param("code");

    // TODO: add state to your oauth url in /auth/add (button) and /auth/direct (direct install) and check it here to make sure there is no XSRF attack going on.
    let state = req.param("state");

    return app.client.oauth.access({
        client_id: <client_id>,
        client_secret: <client_secret>,
        code: code
    }).then(async (result) => {
        // save result of oauth.access call somewhere, like in a database.

        // redirect user afterwards with res.redirect to an url that will say something like "Thanks for installing!" perhaps.
    }).catch((error) => {
        throw error;
    });
});

Is the oAuthV2 not available still?

@Zrce
Copy link

Zrce commented May 10, 2020

Thanks @ErwinAI this is the closest I cam to get this running.

I had to make a few changes.

  1. In express 4 it's

let code = req.query.code;

instead of

let code = req.param("code");

  1. With oauth v2

return app.client.oauth.v2.access({

instead of

return app.client.oauth.access({

And be careful with

const expressReceiver = new ExpressReceiver({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  endpoints: "/events"
});

its probably

const expressReceiver = new ExpressReceiver({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  endpoints: "/slack/events"
});

took me a while to figure it out

@junjizhi junjizhi mentioned this issue Jun 22, 2020
9 tasks
@jparr721
Copy link

I noticed that Bolt has some of the oauth support enabled. Would it be possible to see an example using the bolt API for configuring this system? So far, I have seen the (somewhat outdated) bolt-oauth library on npm, but it looks to be using an old version of the API.

@stevengill
Copy link
Member

@jparr721 I'm not sure I understand what your asking? Want to open a new issue for this? bolt-oauth isn't necessary since OAuth is built into bolt-js now. See https://slack.dev/bolt-js/concepts#authenticating-oauth

@jparr721
Copy link

Sure, thanks @stevengill

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question M-T: User needs support to use the project
Projects
None yet
Development

No branches or pull requests

9 participants