slackapi / java-slack-sdk

Slack Developer Kit (including Bolt for Java) for any JVM language
https://tools.slack.dev/java-slack-sdk/
MIT License
576 stars 214 forks source link

Slash command won't work 401 error from ngrok #1105

Closed YuxiangLiuGC closed 1 year ago

YuxiangLiuGC commented 1 year ago

Hi, my name's Yuxiang Liu. I'm testing the example app with spring boot from GitHub: https://github.com/slackapi/java-slack-sdk/tree/main/bolt-spring-boot-examples/spring-boot-2 I've set the SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET in SlackApp.java and set them as environment variables too. I run ngrok as a proxy server by command: "ngrok http 3000". In the Slash command, I made the "/hello" request URL as "https://c846-173-68-187-137.ngrok.io/slack/events", but the slash command never work. Is there anything I missed?

Reproducible in:

mvn dependency:tree | grep com.slack.api
gradle dependencies | grep com.slack.api
java -version
sw_vers && uname -v # or `ver`

The Slack SDK version

plugins {
    id 'org.springframework.boot' version '2.7.5'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
repositories {
    mavenCentral()
    mavenLocal()
}
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.squareup.okhttp3:okhttp:4.10.0'
    implementation 'com.slack.api:bolt-servlet:[1.27,)'
    implementation("com.slack.api:bolt:1.27.2")
}

Java Runtime version

java version "19" 2022-09-20
Java(TM) SE Runtime Environment (build 19+36-2238)
Java HotSpot(TM) 64-Bit Server VM (build 19+36-2238, mixed mode, sharing)

OS info

Microsoft Windows [Version 10.0.22000.1335]

Steps to reproduce:

  1. SlackApp.java

    @Configuration
    public class SlackApp {
     @Bean
    public AppConfig loadSingleWorkspaceAppConfig() {
        return AppConfig.builder()
                .singleTeamBotToken(System.getenv("xoxb-xxx"))//SLACK_BOT_TOKEN
                .signingSecret(System.getenv("xxx"))//SLACK_SIGNING_SECRET
                .build();
    }
    
    // If you would like to run this app for multiple workspaces,
    // enabling this Bean factory should work for you.
    // @Bean
    
    public AppConfig loadOAuthConfig() {
        return AppConfig.builder()
                .singleTeamBotToken(null)
                .clientId(System.getenv("xxx"))//SLACK_CLIENT_ID
                .clientSecret(System.getenv("xxx"))//SLACK_CLIENT_SECRET
                .signingSecret(System.getenv("xxx"))//SLACK_SIGNING_SECRET
                .scope("app_mentions:read,channels:history,channels:read,chat:write")
                .oauthInstallPath("/slack/install")
                .oauthRedirectUriPath("/slack/oauth_redirect")
                .build();
    }
    
    @Bean
    public App initSlackApp(AppConfig config) {
        App app = new App(config);
        if (config.getClientId() != null) {
            app.asOAuthApp(true);
        }
        app.command("/hello", (req, ctx) -> {
            return ctx.ack(r -> r.text("Thanks!"));
        });
        return app;
    }
    }
  2. SlackAppOAuthController.java
    @WebServlet({"/slack/install", "/slack/oauth_redirect"})
    public class SlackAppOAuthController extends SlackOAuthAppServlet {
    public SlackAppOAuthController(App app) {
        super(app);
    }
    }
  3. SlackAppController.java
    @WebServlet("/slack/events")
    public class SlackAppController extends SlackAppServlet {
    public SlackAppController(App app) {
        super(app);
    }
    }
  4. Application.java

    @SpringBootApplication
    @ServletComponentScan
    public class Application {
    private static String webHookUrl = "https://hooks.slack.com/services/***";
    private static String slackChannel = "epibuildstaff";
    
    public static void main(String[] args) {
        ApplicationContext myapp = new AnnotationConfigApplicationContext(SlackApp.class);
        SpringApplication.run(Application.class, args);
        sendMessageToSlack("EpiBuildStaff Application is up now!");
    }
    
    public static void sendMessageToSlack(String message){
        try {
            StringBuilder msbuilder = new StringBuilder();
            msbuilder.append(message);
    
            Payload payload = Payload.builder().channel(slackChannel).text(msbuilder.toString()).build();
    
            WebhookResponse wbResp = Slack.getInstance().send(webHookUrl, payload);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    }

    Actual result:

    The following are the error messages from Intellij IDE:

    2023-01-05 21:21:42,858 WARN [http-nio-3000-exec-1] com.slack.api.bolt.App Skipped adding any authorization middleware - you need to call app.use(new YourOwnMultiTeamsAuthorization())
    2023-01-05 21:21:42,859 DEBUG [http-nio-3000-exec-1] com.slack.api.bolt.App Applying a middleware (name: com.slack.api.bolt.middleware.builtin.SSLCheck)
    2023-01-05 21:21:42,859 DEBUG [http-nio-3000-exec-1] com.slack.api.bolt.App Applying a middleware (name: com.slack.api.bolt.middleware.builtin.RequestVerification)
    2023-01-05 21:21:42,860 DEBUG [http-nio-3000-exec-1] com.slack.api.app_backend.SlackSignature$Verifier Request verification (timestamp: 1672971702, body: token=vxYEacoMDPfrBG4UPPD54UdA&team_id=T01LLEK1GTT&team_domain=epibuild&channel_id=C04HWA610G1&channel_name=epibuildstaff&user_id=U03MLAR2S9J&user_name=yuxiang&command=%2Fhello&text=&api_app_id=A04HF6PEKHA&is_enterprise_install=false&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT0***&trigger_id=4605743005044.1700495050945.23cc74be12d1318d042521442b14024f, signature: v0=e46791317f7e0989be104bf41fa6079cc0c793fe27c9a69accdf713e3c513bd5)
    2023-01-05 21:21:42,860 INFO [http-nio-3000-exec-1] com.slack.api.bolt.middleware.builtin.RequestVerification Invalid signature detected - v0=e46791317f7e0989be104bf41fa6079cc0c793fe27c9a69accdf713e3c513bd5

    In ngrok terminal:

    HTTP Requests                                                                                                                                                                                                                                                      POST /slack/events             401
    POST /slack/events             401   
misscoded commented 1 year ago

Hi @YuxiangLiuGC! Thanks for submitting your question, and sorry that you're coming across difficulties getting up and running. I'm not as familiar with the Java side of things, but let's see if we can solve the issue at hand. 🙂

The 401 indicates (as does the error) that the signature is invalid. This often is due to a configuration or credential issue.

Taking a look at the code you've provided, if it's being run exactly as seen here, the credentials that are provided for loadSingleWorkspaceAppConfig use System.getenv. If this works the same in Java as it does other languages, I believe you'd want the environment variable names, not the actual values there (Note: I've edited your original message to remove those values).

For example:

@Bean
public AppConfig loadSingleWorkspaceAppConfig() {
      return AppConfig.builder()
              .singleTeamBotToken(System.getenv("SLACK_BOT_TOKEN")) // SLACK_BOT_TOKEN, not value
              .signingSecret(System.getenv("SLACK_SIGNING_SECRET")) // SLACK_SIGNING_SECRET, not value
              .build();
}

After you've double-checked that you've set SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET as environment variables, and that those values are what you'd expect, can you verify that swapping your code out for the original example code doesn't solve the problem?

YuxiangLiuGC commented 1 year ago

@misscoded Thank you! You are genius! I've been looking for the solution for days and it turns out I just misunderstood the code lol.

misscoded commented 1 year ago

So glad you were able to resolve the problem! 😄 I'll close this issue now, but don't hesitate to open a new one if you come across any further difficulties. Happy building!