Skip to content

Commit 5cfe9e8

Browse files
committed
Append OAuth redirect URI to Slack OAuth URL
1 parent 7306192 commit 5cfe9e8

File tree

2 files changed

+80
-15
lines changed

2 files changed

+80
-15
lines changed

bolt/src/main/java/com/slack/api/bolt/App.java

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,11 @@
3636
import lombok.extern.slf4j.Slf4j;
3737

3838
import java.io.IOException;
39+
import java.io.UnsupportedEncodingException;
3940
import java.lang.reflect.Constructor;
4041
import java.lang.reflect.InvocationTargetException;
42+
import java.net.URLEncoder;
43+
import java.nio.charset.StandardCharsets;
4144
import java.util.*;
4245
import java.util.concurrent.atomic.AtomicBoolean;
4346
import java.util.regex.Pattern;
@@ -314,26 +317,60 @@ private void initOAuthServicesIfNecessary() {
314317
}
315318
}
316319

320+
/**
321+
* Get the Slack URL for beginning the OAuth flow, including the query
322+
* params necessary to identify this application to Slack.
323+
*
324+
* Appends the optional `redirect_uri` query param based on the provided
325+
* AppConfig to ensure that the correct OAuth redirect URI is selected in
326+
* cases where a Slack application may have multiple redirect URIs
327+
* associated with it.
328+
*
329+
* @param state The OAuth state param
330+
* @return The Slack URL to redirect users to for beginning the OAuth flow
331+
*/
317332
public String getOauthInstallationUrl(String state) {
318333
AppConfig config = config();
334+
319335
if (config.getClientId() == null || config.getScope() == null || state == null) {
320336
return null;
337+
}
338+
339+
String scope = config.getScope() == null ? "" : config.getScope();
340+
String redirectUriParam = redirectUriQueryParam(appConfig);
341+
342+
if (config.isClassicAppPermissionsEnabled()) {
343+
// https://api.slack.com/authentication/migration
344+
return "https://slack.com/oauth/authorize" +
345+
"?client_id=" + config.getClientId() +
346+
"&scope=" + scope +
347+
"&state=" + state +
348+
redirectUriParam;
321349
} else {
322-
String scope = config.getScope() == null ? "" : config.getScope();
323-
if (config.isClassicAppPermissionsEnabled()) {
324-
// https://api.slack.com/authentication/migration
325-
return "https://slack.com/oauth/authorize" +
326-
"?client_id=" + config.getClientId() +
327-
"&scope=" + scope +
328-
"&state=" + state;
329-
} else {
330-
String userScope = config.getUserScope() == null ? "" : config.getUserScope();
331-
return "https://slack.com/oauth/v2/authorize" +
332-
"?client_id=" + config.getClientId() +
333-
"&scope=" + scope +
334-
"&user_scope=" + userScope +
335-
"&state=" + state;
336-
}
350+
String userScope = config.getUserScope() == null ? "" : config.getUserScope();
351+
return "https://slack.com/oauth/v2/authorize" +
352+
"?client_id=" + config.getClientId() +
353+
"&scope=" + scope +
354+
"&user_scope=" + userScope +
355+
"&state=" + state +
356+
redirectUriParam;
357+
}
358+
}
359+
360+
private String redirectUriQueryParam(AppConfig appConfig) {
361+
if (appConfig.getRedirectUri() == null) {
362+
return "";
363+
}
364+
365+
try {
366+
String urlEncodedRedirectUri = URLEncoder.encode(
367+
appConfig.getRedirectUri(),
368+
StandardCharsets.UTF_8.name()
369+
);
370+
371+
return String.format("&redirect_uri=%s", urlEncodedRedirectUri);
372+
} catch (UnsupportedEncodingException e) {
373+
return "";
337374
}
338375
}
339376

bolt/src/test/java/test_locally/AppTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ public void getOauthInstallationUrl_v1() {
3838
assertEquals("https://slack.com/oauth/authorize?client_id=123&scope=commands,chat:write&state=state-value", url);
3939
}
4040

41+
@Test
42+
public void getOauthInstallationUrl_v1_with_redirect_uri() {
43+
AppConfig config = AppConfig.builder()
44+
.signingSecret("secret")
45+
.clientId("123")
46+
.scope("commands,chat:write")
47+
.classicAppPermissionsEnabled(true)
48+
.redirectUri("https://my.app/oauth/callback")
49+
.build();
50+
App app = new App(config);
51+
String url = app.getOauthInstallationUrl("state-value");
52+
assertEquals("https://slack.com/oauth/authorize?client_id=123&scope=commands,chat:write&state=state-value&redirect_uri=https%3A%2F%2Fmy.app%2Foauth%2Fcallback", url);
53+
}
54+
4155
@Test
4256
public void getOauthInstallationUrl_v2() {
4357
AppConfig config = AppConfig.builder()
@@ -51,6 +65,20 @@ public void getOauthInstallationUrl_v2() {
5165
assertEquals("https://slack.com/oauth/v2/authorize?client_id=123&scope=commands,chat:write&user_scope=search:read&state=state-value", url);
5266
}
5367

68+
@Test
69+
public void getOauthInstallationUrl_v2_with_redirect_uri() {
70+
AppConfig config = AppConfig.builder()
71+
.signingSecret("secret")
72+
.clientId("123")
73+
.scope("commands,chat:write")
74+
.userScope("search:read")
75+
.redirectUri("https://my.app/oauth/callback")
76+
.build();
77+
App app = new App(config);
78+
String url = app.getOauthInstallationUrl("state-value");
79+
assertEquals("https://slack.com/oauth/v2/authorize?client_id=123&scope=commands,chat:write&user_scope=search:read&state=state-value&redirect_uri=https%3A%2F%2Fmy.app%2Foauth%2Fcallback", url);
80+
}
81+
5482
@Test
5583
public void getOauthInstallationUrl_null() {
5684
App app = new App();

0 commit comments

Comments
 (0)