slackapi / bolt-js

A framework to build Slack apps using JavaScript
https://slack.dev/bolt-js
MIT License
2.74k stars 394 forks source link

"Sign in with Slack" is unsupported by Bolt and its underlying OAuth module #1063

Open justman00 opened 3 years ago

justman00 commented 3 years ago

Description

Currently, I am developing a slack app, build with bolt. I have implemented OAuth as suggested here. So, naturally bolt has created this endpoint /slack/install for installing and authorizing the slack app into a workspace, when I (the creator) click it and try to authorize it, it works perfectly fine, however from time to time with some small issuers, but when somebody else from the exterior does it, it always throws an error: Something went wrong when authorizing this app.. Logs:

[DEBUG]  web-api:WebClient:0 initialized
[DEBUG]  web-api:WebClient:0 apiCall('oauth.v2.access') start
[DEBUG]  web-api:WebClient:0 will perform http request
[DEBUG]  web-api:WebClient:0 http response received
[DEBUG]  web-api:WebClient:1 initialized
[DEBUG]  web-api:WebClient:1 apiCall('auth.test') start
[DEBUG]  web-api:WebClient:1 will perform http request
[DEBUG]  web-api:WebClient:1 http response received
[DEBUG]  web-api:WebClient:2 initialized
[DEBUG]  web-api:WebClient:2 apiCall('auth.test') start
[DEBUG]  web-api:WebClient:2 will perform http request
[DEBUG]  web-api:WebClient:2 http response received
[ERROR]  OAuth:InstallProvider:0 Error: An API error occurred: invalid_auth
    at Object.platformErrorFromResult (/path-to-/node_modules/@slack/web-api/dist/errors.js:51:33)
    at WebClient.apiCall (/path-to-/node_modules/node_modules/@slack/web-api/dist/WebClient.js:158:28)
    at processTicksAndRejections (internal/process/task_queues.js:93:5) {
  code: 'slack_webapi_platform_error',
  data: {
    ok: false,
    error: 'invalid_auth',
    response_metadata: { scopes: [Array] }
  }
}
[DEBUG]  OAuth:InstallProvider:0 calling passed in options.failure

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

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


Bug Report

Here is the code:

import { App, LogLevel, ExpressReceiver } from '@slack/bolt';
import { Low, JSONFile } from 'lowdb';
import { join } from 'path';
import { sendWelcomeMessage } from './views/messages.js';
import { createUserProfile } from './auth/authGetTilo.js';
import { newUserHomePage } from './views/homePage.js';

const file = join('./db.json');
const adapter = new JSONFile(file);
const db = new Low(adapter);

const receiver = new ExpressReceiver({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  logLevel: LogLevel.DEBUG,
  clientId: process.env.SLACK_CLIENT_ID,
  clientSecret: process.env.SLACK_CLIENT_SECRET,
  stateSecret: 'someStateSecret',
  scopes: ['commands', 'chat:write'],
  installationStore: {
    storeInstallation: async (installation) => {
      // change the line below so it saves to your database
      console.log('installation', installation);
      await db.read();
      db.data = db.data || {};
      db.data.installation = installation;
      await db.write();
      // save to db

      sendWelcomeMessage(app, installation);
      createUserProfile(app, installation, db)
    },
    fetchInstallation: async (installQuery) => {
      // change the line below so it fetches from your database
      console.log('installQuery', installQuery);
      await db.read();
      if (db.data.installation) {
        return db.data.installation;
      }

      throw new Error('Failed fetching installation');
    },
    deleteInstallation: async (installQuery) => {
      // change the line below so it deletes from your database
    },
  },
  installerOptions: {
    userScopes: ['identity.basic', 'identity.email'],
    callbackOptions: {
      success: (installation, installOptions, req, res) => {
        res.end('success');
      },
      failure: (error, installOptions, req, res) => {
        res.end('failure');
      },
    },
  },
});

const app = new App({ receiver });

// All the room in the world for your code
app.event('app_home_opened', params => newUserHomePage(params, db));

(async () => {
  // Start your app
  await app.start(process.env.PORT || 3000);

  console.log('⚡️ Bolt app is running!');
})();

please ignore the LowDB part, it's just for testing

Reproducible in:

package version: "^3.5.0"

node version: v14.13.1

OS version(s): macOS Big Sur

Expected result:

Users are able to correctly authorize the app

Actual result:

An error is being thrown, without any message on how to solve it

seratch commented 3 years ago

Hi @justman00, thanks for asking the question!

userScopes: ['identity.basic', 'identity.email'],

Your app cannot have identity.* user scopes along with others such as commands. When your app has those, only identity.* should be passed to the authorize URL. If you need some user token scopes, other user scopes can co-exist with bot scopes.

Also, we've recently renewed "Sign in with Slack" to make it compatible with OpenID Connect. The new way requires openid, email (optional), profile (optional) instead of identity.*. If you are building a new app using "Sign in with Slack" functionality, consider the latest one for it. https://api.slack.com/authentication/sign-in-with-slack

I hope this was helpful to you!

justman00 commented 3 years ago

I did remove the commands scope but the issue seems to be happening still, after revoking my own access, I can reproduce this all the time

seratch commented 3 years ago

Hi @justman00, I checked this issue today and found that @slack/bolt and its underlying @slack/oauth package do not support "Sign in with Slack" feature at this moment.

We may update the package to support the functionality in the future (we haven't decided it yet) but in the short term, please consider implementing the "Sign in with Slack" flow on your own. The code should be quite simple. Here is a simple example app built with Koa: https://github.com/slackapi/node-slack-sdk/pull/1310

I hope this was helpful to you.

justman00 commented 3 years ago

thank you @seratch looking forward to what's next for the bolt framework and its integrations

ErwinAI commented 2 years ago

@seratch Quick heads-up that the Slack API documentation for the new OpenID method openid.connect.token is inaccurate (see screenshot).

image

The App Review team already asked us to update our sign-in with the new OpenID tokens but this means that we have to do a manual post request (we do everything with BoltJS until now) and then later change again if Bolt 3.11.0 comes out 😅

seratch commented 2 years ago

@ErwinAI Indeed, the "Powered by Bolt" part is incorrect but it just means that client.openid.connection.token({ ... }) is available in your App instance.

We still have this task in the milestone v3.11 now. However, probably we have to move it to v3.12 or newer version. We are mainly working on other OAuth related improvements in the release and it still requires my time.

For the time being, please consider going with your own implementation that directly use the underlying API client. Here is an example for the OpenID Connect compatible one: https://github.com/slackapi/node-slack-sdk/blob/main/examples/openid-connect/app.js

That being said, I understand that, if bolt-js supports it out-of-the-box, it's much simpler and easier-to-maintain for developers. We will work on the enhancement in the near future.

SujayPrabhu96 commented 1 year ago

Hi @seratch Any updates on this feature ? When can we expect it ?

seratch commented 1 year ago

Hi @SujayPrabhu96, no updates on this so far. Also, we may not be able to work on it for a while due to our priorities.

Implementing your server-side for "Sign in with Slack" is relatively simple. So, if you need to add the feature to your app right now, please consider having additional code like this. If you want to add it to your existing bolt-js app, implementing OpenID Connect handlers as custom routes is an option too.

SujayPrabhu96 commented 1 year ago

Great, thank you @seratch