サイトにSlackで共有ボタンを設置する

# 概要
LINEで送るの様なSNS共有ボタンのSlack版をサービスサイトへ設置する手順。
LINEで送ると同じ様に「ユーザー名」で「指定ユーザー」に共有できることを目的とします。

[LINEで送る](https://social-plugins.line.me/ja/how_to_install#lineitbutton)はこちらを参照してください。

## 利用するSlack API Method

メッセージを送るだけならばIncoming webhooksを利用する方法もありますが、今回は上記の条件でメッセージをユーザー TO ユーザーで送りたいので、下記のAPI METHODを利用します。

[oauth.access](https://api.slack.com/methods/oauth.access)
[chat.postMessage](https://api.slack.com/methods/chat.postMessage)

※注意するポイントは*OAuthv2*ではなく*OAuth*の方で実現することです。

# SlackにAppを作成する

https://api.slack.com/　にアクセスしてAppを作成します。
![スクリーンショット 2020-03-01 16.17.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/942b635c-404b-e6c8-f52a-2cd3dec382cb.png)

こちらのStart Buildingボタンを押すと以下のページに遷移します。
![スクリーンショット 2020-03-01 16.20.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/62fdc3ea-ad02-c3c5-c9d8-153989a91661.png)

しかし、ここのCreate Slack Appを指定して作成してしまうとOAuth v2で作成されてしまうため、閉じるボタンを押してスキップします。

左メニューの
_Installation & permissions_ > _Installing with OAuth_ を選択しページを遷移
ページ最下部まで移動してCreate classic Slack appボタンを押してください。

![スクリーンショット 2020-03-01 16.26.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/b075170d-4ffe-72a5-965e-3d3bee2c721c.png)

これでOauthのAppが作成できます。

まずOauth認証に必要な_Client ID_と_Client Secret_を
_Settings_ > _Basic Information_ のApp Credentialsから保存してください。
適当にテキストファイル等にコピーしておいてください。(もちろん取り扱い注意)

## SlackAppを動く状態にする

OAuth認証の設定をしてSlackAppが動く様に登録していきます。

_Features_ > _OAuth & Permissions_ より<b>Redirect URLs</b>と<b>Scope</b>の登録をします。

![スクリーンショット 2020-03-01 16.45.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/762a985c-6941-20ea-6476-0a105d9d8e63.png)

リダイレクトURLはコールバックを受けるURLでSlackの認証ページから戻ってくる、またはSlack側のエラー画面で利用する戻るボタンに設置されます。

![スクリーンショット 2020-03-01 16.49.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/7cfc4d9e-d57f-67d9-fe1f-293d93a016cf.png)

Scopeは今回作成するAppが利用できる権限の設定を行う場所です。
※今回はClassicAppで作成しているので設定は１箇所ですが、OAuth２の場合はBotのScopeとUserのScopeの２種類指定する必要があります。

今回は「chat:write:user」と「incoming-webhook」の２つを指定してください。
こちらが<b>「ユーザー」</b>が<b>「指定ユーザー」</b>に共有するための権限です。

ここまで設定すると
_Settings_ > _Manage Distribution_ に_Sharable URL_が表示され、これが認証に利用するURLとなるので保存しておいてください。
![スクリーンショット 2020-03-01 17.03.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/2698a8e1-9483-036b-29ce-e7c70163905c.png)

また、App Suggestions HTMLのMETAタグを上記Appを動かすページへ貼り付けてください。

これでAppが動く様になりました。

ただし、この状態では自分の（Appが作成された）ワークスペースでしかメッセージを送ることができません。

先ほどの_Sharable URL_以下の様な黒い画面になるはずです。

![スクリーンショット 2020-03-01 23.41.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/730d950b-527d-0557-0a35-890d362718b1.png)


## 別のワークスペースを選択できる様にする
今の状態だとこのAppが作成されたワークスペースしかメッセージを送ることができないので、OAuth認証ページで別のワークスペースを表示する設定をします。

_Settings_ > _Manage Distribution_ > _Share Your App with Other Workspaces_の_Remove Hard Coded Information_の項目を有効にする必要があります。

その他の項目は今までの手順で有効（チェック済み）の状態になっているはずなので
こちらのI’ve reviewed and removed any hard-coded information.のチェックボックスにチェックを入れてActivate Public Distribustionボタンを押してください。

![スクリーンショット 2020-03-01 23.50.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/94f5996a-69ea-c527-75ba-f408bd4a6c2f.png)

すると以下の様にSlackのAppディレクトリへの申請画面となります。とりあえず公式Appとせずシェア機能だけのテストなので申請は行いませんが、Scopeに関する説明を付与する必要があります。

![スクリーンショット 2020-03-01 23.58.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/79f69027-bc2e-9e63-8854-b8e179e97ff6.png)

適当に英語で理由を申請してください。

![スクリーンショット 2020-03-02 0.01.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/fe0a7e1b-cb5b-5084-7e13-34ac2c76da13.png)

この_Review your permission scopes_の項目にすべてチェックが入れば晴れて公開Appとなり他のワークスペースへインストールすることができます。

_Sharable URL_へもう一度アクセスすると下記の様に右上にワークスペースを選択するコンボボックスが表示されます。

![スクリーンショット 2020-03-02 0.06.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/2106760c-14c1-ccd5-12c5-3232d95a1a37.png)

これで<b>LINEで送る</b>と同じ様に
<b>ユーザー</b>が<b>指定ユーザー</b> に共有する準備ができました。

※ちなみに<b>scope</b>にincoming-webhookを指定した理由はOAuth認証画面に宛先追加のプルダウンを表示したかったからです。
![スクリーンショット 2020-03-02 0.13.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594923/221075ae-4a24-743f-f401-e6f022dc4978.png)

自分で宛先追加プルダウンを作る場合は他のMethodを使って自作してください。

# コールバックを受けるプログラムを作る（Redirect_URL）

先ほどの認証画面で許可をする、またはキャンセルするとコールバックURLへcodeというパラメータがGETで帰ってきます。

このcodeをoauth.accessメソッドに渡してaccess_tokenを取得することでAppが権限を得ることができます。

以下簡単なコード（PHP）を記載しておきますので参考にしてください。

```
<?php
if($_GET['code'] != '')
{
    $share = $_GET['share_url']; /* /oauth/authorizeにあらかじめ共有URLを渡しておくと、コールバック時に返してくれます */
    $url = 'https://slack.com/api/oauth.access';
    $params['client_id'] = 'ここにクライアントID';
    $params['client_secret'] = 'ここにclient_secret';
    $params['redirect_uri'] = '自分自身のURL（redirect_uriで指定）'
    $params['code'] = $_GET['code'];
    $queryString = http_build_query($params, null, '&');
    $header = array(
        "Content-Type: application/x-www-form-urlencoded",
        "Content-Length: ".strlen($queryString)
    );
    /* oauth.access は x-www-form-urlencodedしか受け付けない */
    $options = array(
        "http" => array(
        "method"  => "POST",
        "header"  => implode("\r\n", $header),
        "content" => $queryString
        )
    );
    /* アクセストークンの取得 */
    $result = file_get_contents($url,false, stream_context_create($options));

    $json = json_decode($result,true);

    if($json['ok'] != true)
    {
        print('問題が発生しました');
        return;
    }
    $payload['text'] = "共有です。<" . $share . "|ここ>";
    $payload['channel'] = $json['incoming_webhook']['channel'];
    $payload['as_user'] = 'true'; /* これを指定するとユーザーとしてメッセージを送ります */
    /* こちらはJsonで送れますがcharsetを送らないと叱られます. */
    /* access_tokenはここで指定してください。 */
    $header = array(
        "Content-Type:  application/json charset=utf-8;",
        'Authorization: Bearer ' . $json['access_token']
    );
    $options = array(
        'http' => array(
            'method' => 'POST',
            'header' => implode("\r\n", $header),
            'content' => json_encode($payload),
        )
    );
    /* message発射！！ */
    $response = file_get_contents('https://slack.com/api/chat.postMessage',false, stream_context_create($options));
}
?>
<html>
    <head>
        <script>location.replace(<?=$share?>);</script>
    </head>
    <body>
        移動しますね。
    </body>
</html>
```
これでアクセストークンをDBに保存するなり、PHPのSESSION等を利用してシームレスに動く様にするなど工夫すれば完成すると思います。