Skip to content

Commit fbed1a4

Browse files
authored
Fix #799 Add OpenID Connect document (#805)
* Fix #799 Add OpenID Connect document * Update the OpenID Connect document
1 parent 67d5fac commit fbed1a4

File tree

6 files changed

+301
-3
lines changed

6 files changed

+301
-3
lines changed

docs/_includes/sidebar-ja.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/ja/events-api">イベント API</a></li>
2323
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/ja/steps-from-apps">ワークフローステップ</a></li>
2424
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/ja/app-distribution">アプリの配布 (OAuth)</a></li>
25+
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/ja/sign-in-with-slack">Slack でログインする</a></li>
2526
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/ja/supported-web-frameworks">対応 Web フレームワーク</a></li>
2627
</ul>
2728
</li>

docs/_includes/sidebar.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/events-api">Events API</a></li>
2323
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/steps-from-apps">Workflow Steps</a></li>
2424
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/app-distribution">App Distribution (OAuth)</a></li>
25+
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/sign-in-with-slack">Sign in with Slack</a></li>
2526
<li class="toctree-l2"><a href="{{ site.url | append: site.baseurl }}/guides/supported-web-frameworks">Supported Web Frameworks</a></li>
2627
</ul>
2728
</li>

docs/guides/app-distribution.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Technically, it's possible to use a single **App** for both Slack API requests a
7171

7272
### Slack Config for Distributing Your Slack App
7373

74-
Here is the list of the necessary configurations for distributing apps built with Bolt. If you prefer using other env variable names or other solutions to load this information, implement your own way to load **SlackConfig** instead.
74+
Here is the list of the necessary configurations for distributing apps built with Bolt. If you prefer using other env variable names or other solutions to load this information, implement your own way to load **AppConfig** instead.
7575

7676
|Env Variable Name|Description (Where to find the value)|
7777
|-|-|
@@ -147,6 +147,8 @@ SlackAppServer server = new SlackAppServer(Map.of(
147147
server.start(); // http://localhost:3000
148148
```
149149

150+
If you want to turn [the token rotation feature](https://api.slack.com/authentication/rotation) on, your `InstallationService` should be compatible with it. Refer to the [v1.9.0 release notes](https://github.com/slackapi/java-slack-sdk/releases/tag/v1.9.0) for more details.
151+
150152
### Granular Permission Apps or Classic Apps
151153

152154
Slack has two types of OAuth flows for Slack app installations. The V2 (this is a bit confusing but it's not the version of OAuth spec, but the version of the Slack OAuth flow) OAuth flow enables Slack apps to request more granular permissions than the classic ones, especially for bot users. The differences between the two types are having `v2` in the endpoint to issue access tokens and the OAuth Authorization URL, plus some changes to the response data structure returned by the `oauth(.v2).access` endpoint.

docs/guides/ja/app-distribution.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ server.start(); // http://localhost:3000
7070

7171
### 配布可能な Slack アプリのための設定
7272

73-
以下は配布可能なアプリのための設定項目の一覧です。もしこれら以外の環境変数名や、別の読み込みの仕組みを使いたい場合は、自前で **SlackConfig** を初期化する実装を行ってください。
73+
以下は配布可能なアプリのための設定項目の一覧です。もしこれら以外の環境変数名や、別の読み込みの仕組みを使いたい場合は、自前で **AppConfig** を初期化する実装を行ってください。
7474

7575
|環境変数名|説明 (値を見つけられる場所)|
7676
|-|-|
@@ -80,7 +80,7 @@ server.start(); // http://localhost:3000
8080
|**SLACK_REDIRECT_URI**|**OAUth 2.0 Redirect URI** (**Features** > **OAuth & Permissions** > **Redirect URLs**)|
8181
|**SLACK_SCOPES**|**カンマ区切りの bot scope リスト**: `scope` パラメーターは `https://slack.com/oauth/authorize``https://slack.com/oauth/v2/authorize` にクエリパラメーターとして付加されます (**Settings** > **Manage Distribution** > **Sharable URL** から `scope` の値を取得)|
8282
|**SLACK_USER_SCOPES** (v2 のみ)|**カンマ区切りの user scope リスト**: `user_scope` パラメーターは `https://slack.com/oauth/v2/authorize` にクエリパラメーターとして付加されます (**Settings** > **Manage Distribution** > **Sharable URL**, から `user_scope` の値を取得)|
83-
|**SLACK_INSTALL_PATH**|**OAuth フローの開始点**: このエンドポイントはユーザーを `client_id`, `scope`, `user_scope` (v2 のみ), and `state` とともに Slack の Authorize エンドポイントにリダイレクトします。推奨するパスは `/slack/oauth/start` ですが、どのようなパスでも構いません。|
83+
|**SLACK_INSTALL_PATH**|**OAuth フローの開始点**: このエンドポイントはユーザーを `client_id`, `scope`, `user_scope` (v2 のみ), `state` とともに Slack の Authorize エンドポイントにリダイレクトします。推奨するパスは `/slack/oauth/start` ですが、どのようなパスでも構いません。|
8484
|**SLACK_REDIRECT_URI_PATH**|**OAuth Redirect URI**: このエンドポイントは Slack の OAuth 許可確認画面からの callback リクエストを処理します。このパスは **SLACK_REDIRECT_URI** の値と整合している必要があります。推奨のパスは `/slack/oauth/callback` ですが、どのようなパスでも構いません。|
8585
|**SLACK_OAUTH_COMPLETION_URL**|**Installation Completion URL**: インストール完了画面の URL を指定します。どんな URL でも構いません。|
8686
|**SLACK_OAUTH_CANCELLATION_URL**|**Installation Cancellation/Error URL**: キャンセルやエラーが発生したときの遷移先 URL を指定します。どんな URL でも構いません。|
@@ -146,6 +146,8 @@ SlackAppServer server = new SlackAppServer(Map.of(
146146
server.start(); // http://localhost:3000
147147
```
148148

149+
もし[トークンローテーション](https://api.slack.com/authentication/rotation)を有効にしたいという場合は、あなたの `InstallationService` がトークンローテーション互換である必要があります。詳細は [v1.9.0 のリリースノート(英語)](https://github.com/slackapi/java-slack-sdk/releases/tag/v1.9.0)を参考にしてください。
150+
149151
### Granular Permission Apps と Classic Apps
150152

151153
Slack アプリインストールには、二つの OAuth フローがあります。V2(ちょっと紛らわしいですが OAuth のバージョンではなく Slack OAuth フローのバージョンです)の OAuth フローでの Slack アプリは(特にボットユーザーの権限に関して)旧来に比べてより詳細な必要最小限の権限だけをリクエストできるようになりました。二つのやり方の違いは `v2` を Authorization URL やトークンを発行する API メソッドの URL に含んでいることと、API レスポンスのデータ構造に若干の変更が加わっていることです。
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
layout: ja
3+
title: "Slack でログインする (OpenID Connect)"
4+
lang: ja
5+
---
6+
7+
# Slack でログインする (OpenID Connect)
8+
9+
[Slack でログインする (Sign in with Slack)](https://api.slack.com/authentication/sign-in-with-slack)という機能は、ユーザーが Slack アカウントを使って他のサービスにログインすることに役立ちます。このプラットフォーム機能は、標準の [OpenID Connect](https://openid.net/connect/) の仕様と互換性を持つように最近アップグレードされました。Bolt for Java の 1.10 以上のバージョンであれば、この認証フローを非常に簡単に実装することができます。
10+
11+
### Slack アプリの設定
12+
13+
新しい Slack アプリをつくるときに、以下のユーザースコープを設定してください:
14+
15+
```yaml
16+
oauth_config:
17+
redirect_urls:
18+
- https://example.com/replace-this-with-your-own-redirect-uri
19+
scopes:
20+
user:
21+
- openid # 必須
22+
- email # オプショナル
23+
- profile # オプショナル
24+
```
25+
26+
27+
### OpenID Connect アプリのための設定
28+
29+
以下は OpenID Connect 互換のアプリのための設定項目の一覧です。もしこれら以外の環境変数名や、別の読み込みの仕組みを使いたい場合は、自前で **AppConfig** を初期化する実装を行ってください。
30+
31+
|環境変数名|説明 (値を見つけられる場所)|
32+
|-|-|
33+
|**SLACK_CLIENT_ID**|**Client ID** (Find at **Settings** > **Basic Information** > **App Credentials**)|
34+
|**SLACK_CLIENT_SECRET**|**Client Secret** (Find at **Settings** > **Basic Information** > **App Credentials**)|
35+
|**SLACK_REDIRECT_URI**|**Redirect URI** (Configure at **Features** > **OAuth & Permissions** > **Redirect URLs**)|
36+
|**SLACK_USER_SCOPES**|**カンマ区切りの user scope リスト**: `scope` パラメーターは `https://slack.com/openid/connect/authorize` にクエリパラメーターとして付加されます。可能な値は `openid`, `email`, `profile` です。|
37+
|**SLACK_INSTALL_PATH**|**OpenID Connect フローの開始点**: このエンドポイントはユーザーを `client_id`, `scope`, `state`, `nonce` (オプショナル) のクエリパラメーターとともに Slack の OpenID Connect エンドポイントにリダイレクトします。|
38+
|**SLACK_REDIRECT_URI_PATH**|**OpenID Connect Redirect URI**: このエンドポイントは Slack の OAuth 許可確認画面からの callback リクエストを処理します。このパスは **SLACK_REDIRECT_URI** の値と整合している必要があります。|
39+
40+
### コード例
41+
42+
どのようにエンドユーザーの OpenID Connect のフローをハンドリングするかを知るには、[Servlet アプリの例](https://github.com/slackapi/java-slack-sdk/blob/main/bolt-servlet/src/test/java/samples/OpenIDConnectSample.java)を参考にしてみてください。
43+
44+
```java
45+
import java.util.*;
46+
47+
// implementation 'com.slack.api:bolt-jetty:{the latest version}'
48+
import com.slack.api.Slack;
49+
import com.slack.api.bolt.App;
50+
import com.slack.api.bolt.jetty.SlackAppServer;
51+
52+
// id_token の JWT の値をでコードしたい場合は、以下の外部ライブラリを使う:
53+
// implementation 'com.auth0:java-jwt:{the latest version}'
54+
import com.auth0.jwt.JWT;
55+
import com.auth0.jwt.interfaces.Claim;
56+
import com.auth0.jwt.interfaces.DecodedJWT;
57+
58+
// 以下の環境変数が設定されていることが前提:
59+
// SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_REDIRECT_URI, SLACK_USER_SCOPES
60+
App app = new App().asOpenIDConnectApp(true);
61+
62+
// このコールバック関数で OpenID Connect の code authorization フローをハンドリングできる
63+
app.openIDConnectSuccess((req, resp, token) -> {
64+
var logger = req.getContext().getLogger();
65+
66+
// TODO: 渡された "token" レスポンス (openid.connect.token API 応答) を保存
67+
68+
// openid.connect.token レスポンスの id_token をデコード
69+
DecodedJWT decoded = JWT.decode(token.getIdToken());
70+
Map<String, Claim> claims = decoded.getClaims();
71+
logger.info("claims: {}", claims);
72+
73+
var teamId = claims.get("https://slack.com/team_id").asString();
74+
75+
// 取得したアクセストークンで openid.connect.userInfo API を呼び出す実装例
76+
var client = Slack.getInstance().methods();
77+
try {
78+
var userInfo = client.openIDConnectUserInfo(r -> r.token(token.getAccessToken()));
79+
logger.info("userInfo: {}", userInfo);
80+
81+
} catch (Exception e) {
82+
throw new RuntimeException(e);
83+
}
84+
85+
// エンドユーザーにWebページを表示(または、他のサービスとの OAuth フローに続けるなどどこかにリダイレクトしてもよい)
86+
var html = app.config().getOAuthRedirectUriPageRenderer().renderSuccessPage(
87+
null, req.getContext().getOauthCompletionUrl());
88+
resp.setBody(html);
89+
resp.setContentType("text/html; charset=utf-8");
90+
return resp;
91+
});
92+
93+
Map<String, App> apps = new HashMap<>();
94+
apps.put("/slack/", app);
95+
SlackAppServer server = new SlackAppServer(apps);
96+
server.start();
97+
```
98+
99+
もし、[トークンローテーション(英語)](https://api.slack.com/authentication/rotation)の機能も同時に有効にする場合、コードは以下のようになるでしょう:
100+
101+
```java
102+
// このコールバック関数で OpenID Connect の code authorization フローをハンドリングできる
103+
app.openIDConnectSuccess((req, resp, token) -> {
104+
var logger = req.getContext().getLogger();
105+
106+
// TODO: 渡された "token" レスポンス (openid.connect.token API 応答) を保存
107+
108+
// openid.connect.token レスポンスの id_token をデコード
109+
DecodedJWT decoded = JWT.decode(token.getIdToken());
110+
Map<String, Claim> claims = decoded.getClaims();
111+
logger.info("claims: {}", claims);
112+
113+
var teamId = claims.get("https://slack.com/team_id").asString();
114+
115+
// 取得したアクセストークンで openid.connect.userInfo API を呼び出す実装例
116+
var client = Slack.getInstance().methods();
117+
try {
118+
if (token.getRefreshToken() != null) {
119+
// はじめてのトークンローテーションをするコード例
120+
var refreshedToken = client.openIDConnectToken(r -> r
121+
.clientId(config.getClientId())
122+
.clientSecret(config.getClientSecret())
123+
.grantType("refresh_token")
124+
.refreshToken(token.getRefreshToken())
125+
);
126+
127+
var teamIdWiredClient = Slack.getInstance().methods(refreshedToken.getAccessToken(), teamId);
128+
var userInfo = teamIdWiredClient.openIDConnectUserInfo(r -> r.token(refreshedToken.getAccessToken()));
129+
logger.info("userInfo: {}", userInfo);
130+
131+
} else {
132+
throw new RuntimeException("Unexpectedly refresh token is absent");
133+
}
134+
135+
} catch (Exception e) {
136+
throw new RuntimeException(e);
137+
}
138+
139+
// エンドユーザーにWebページを表示(または、他のサービスとの OAuth フローに続けるなどどこかにリダイレクトしてもよい)
140+
var html = app.config().getOAuthRedirectUriPageRenderer().renderSuccessPage(
141+
null, req.getContext().getOauthCompletionUrl());
142+
resp.setBody(html);
143+
resp.setContentType("text/html; charset=utf-8");
144+
return resp;
145+
});
146+
```

0 commit comments

Comments
 (0)