61
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SlackのOAuth認証を使ってユーザ情報を取得してみた

Last updated at Posted at 2019-05-24

SlackのOAuth2を利用することになり、作業前は細かい動作がピンとこなかったので手順をまとめておきます。
Slackのユーザ情報を取得する実際のコードも載せています。

SlackのOAuth2.0については以下を参考にしました。
SlackでOAuth2を利用したときのメモ
Using OAuth 2.0 | Slack

手順概要

ざっくり以下の流れが必要になります。

  1. Slackアプリに登録する
  2. Slackアプリの権限設定などを行う
  3. 認可コードを受け取るコールバックサーバを立てる
  4. Webブラウザで認可リクエスト投げる
  5. コールバックサーバで認可コードを受け取り、そのコードを含めたリクエストを投げる

Slackアプリの登録

まず、Slackアプリを登録します

Slack API: Applications | Slack を開いて、Create New App を選択して、任意のアプリ名とチームを選択してください。

ClientIDの取得

Basic Informationのページの画面中央のApp CredentialsにIDが書いてあります

Client IDClient Secretが必要になるので控えておいてください。(漏洩しないよう注意)

ただ、いつでも見えるので後でも良いです。

oauth_client_id.png

Recirect URLsの設定

左メニューより、OAuth & Permissionsを選択します。

Redirect URLsの項目からコールバックを受けるサーバのURLを追加します。

今回はローカルサーバに立てるので、http://localhost:3000を登録します。

oauth_redirecturl.png

Scopeの設定

画面下部のScopes中のSelect Permission Scopesからusers:readを選択します

oauth_users_read.png

認可のみであればidentity.basicでも良いのですが、サンプルコードではユーザ情報まで取得しているため、これを選択します

ここまででSlack側の設定は完了です

OAuth認証を行うためにはコールバックを受け取るためのサーバが必要になります。
実際のアプリの場合はグローバルなサーバとなりますが、今回は確認なのでローカルホストにサーバを起動します。

サンプルコードは dbgso/slack-oauth2.0-client にあげています。
内容はコードの中身をみてください

#コードの取得

git clone https://github.com/dbgso/slack-oauth2.0-client.git
cd slack-oauth2.0-client
yarn # or npm install

クライアントIDの設定

任意のエディタでapp.jsを編集して、SlackのクライアントIDを設定してください。
IDはClientの取得で控えておいたものです。

// Slack App の Client ID
- const slack_client_id = '';
+ const slack_client_id = '実際のclient_id';
// Slack App の Client Secret
- const slack_client_secret = ''
+ const slack_client_secret = '実際のclient_secret'

起動

node app.js

これでhttp://localhost:3000にSlackからのコールバックを受け取るサーバが立ち上がります。

Webブラウザから認可リクエスト

Webブラウザで以下のURLを開きます

SLACK_CLIENT_IDの部分は実際のclient_idに合わせてください。それ以外は変更なしで大丈夫です

https://slack.com/oauth/authorize?client_id=<SLACK_CLIENT_ID>&scope=identify&redirect_uri=http://localhost:3000/

以下のような画面が表示されるはずです。
ここでAuthorizeボタンを押すとredirect_uriで指定したhttp://localhost:3000に対してリクエストが送られます。

slack-auth

実行結果

Slackのユーザ情報を取得するまでの流れは以下のようになっています。
認可するのみであれば6.のユーザ情報取得までは必要ありません。

  1. Authorizedボタンを押下する
  2. http://localhost:3000にHTTPリクエストが飛ぶ
  3. HTTPリクエストのクエリ中に認可コードが含まれているので取得
  4. 認可コードを使ってhttps://slack.com/api/oauth.accessにリクエストしてアクセストークンを取得
  5. アクセストークンを使ってhttps://slack.com/api/auth.testにリクエストしてuser_idを取得
  6. user_idを使ってhttps://slack.com/api/users.infoにリクエストして、Slack上のユーザ情報を取得する

うまく行けば以下のようなログがコンソール上に流れるはずです。

アクセストークン取得

https://slack.com/api/oauth.accessからのレスポンス

{ ok: true,
  access_token:
   '****-**********-************-************-********************************',
  scope: 'read,identify',
  user_id: '*********',
  team_name: '******',
  team_id: '*********' }

user_id取得

https://slack.com/api/auth.testからのレスポンス

{ ok: true,
  url: 'https://******.slack.com/',
  team: '******',
  user: '*****',
  team_id: '*********',
  user_id: '*********' }

Slackユーザ情報取得

https://slack.com/api/users.infoからのレスポンス

自身のSlackユーザ情報が表示されます。この情報は別にいらない、ということであればhttps://slack.com/api/users.infoへのリクエスト処理は不要です。

{
    "ok": true,
    "user": {
        "id": "**********",
        "team_id": "**********",
        "name": "**********",
        "deleted": false,
        "color": "d58247",
        "real_name": "**********",
        "tz": "Asia/Tokyo",
        "tz_label": "Japan Standard Time",
        "tz_offset": 32400,
        "profile": {
            "title": "",
            "phone": "",
            "skype": "",
            "real_name": "**********",
            "real_name_normalized": "**********",
            "display_name": "**********",
            "display_name_normalized": "**********",
            "status_text": "",
            "status_emoji": "",
            "status_expiration": 0,
            "avatar_hash": "**********",
            "image_original": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_original.jpg",
            "email": "**********",
            "first_name": "***",
            "last_name": "***",
            "image_24": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_24.jpg",
            "image_32": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_32.jpg",
            "image_48": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_48.jpg",
            "image_72": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_72.jpg",
            "image_192": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_192.jpg",
            "image_512": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_512.jpg",
            "image_1024": "https://avatars.slack-edge.com/xxxx-xx-xx/****************_1024.jpg",
            "status_text_canonical": "",
            "team": "**********",
            "is_custom_image": true
        },
        "is_admin": false,
        "is_owner": false,
        "is_primary_owner": false,
        "is_restricted": false,
        "is_ultra_restricted": false,
        "is_bot": false,
        "is_app_user": false,
        "updated": 1557212637,
        "has_2fa": false
    }
}

失敗時ログ

こんなログが流れている場合は認可が失敗しています。

client_idが正しいか、Redirect URLsPermissionsの設定を見直してみてください。

{ ok: false, error: 'invalid_code' }
{ ok: false, error: 'not_authed' }

認可のみであればidentity.basicでも良いのですが、サンプルコードではユーザ情報まで取得しているため、これを選択します

ちなみに、こう書きましたが、identity.basicを選んだ状態で、ユーザ情報を取得しようとすると以下のようなエラーがでます。

{"ok":false,"error":"missing_scope","needed":"users:read","provided":"identify"}

コードの中身

  • Node.js v10.15.3
  • express 4.17
  • request 2.88

でコールバックサーバを立てました。
リクエスト処理の度にネストが深くなってしまってみづらいですが、50行程度なので逆に小細工するよりこっちの方がみやすいかなと思ってます。

requestをPromiseにしてくれ...
と思ったらあるんですね。試しておきます
request-promiseを使ったHTTPクライアントを作る - Qiita

app.js
//@ts-check

const request = require('request')
const express = require('express');
const app = express();

// SSL関連でエラーが出るので、応急処置 SlackのAPIにリクエストするときに死んでいる模様。おそらく社内ネットワークのせい
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0";

// Slack App の Client ID
const slack_client_id = '';
// Slack App の Client Secret
const slack_client_secret = ''

app.get('/', (req, res) => {
    // 認可コードの取得
    const code = req.query["code"];

    // 認可コードを使って、アクセストークンをリクエストする
    request({
        url: "https://slack.com/api/oauth.access",
        method: "POST",
        form: {
            client_id: slack_client_id,
            client_secret: slack_client_secret,
            code: code,
            redirect_uri: "http://localhost:3000/"
        }
    }, (error, response, body) => {
        // レスポンスからアクセストークンを取得する
        const param = JSON.parse(body);
        console.log(param);
        const access_token = param['access_token']; // アクセストークン

        // ユーザIDを取得するためのリクエスト
        request("https://slack.com/api/auth.test",{
            method: "POST",
            form: {
                token: access_token
            }
        },(error, response, body) => {
            console.log(JSON.parse(body));
            // アクセストークンを使ってユーザ情報をリクエスト
            // 認可のみが目的の場合はここはなくても良い
            request("https://slack.com/api/users.info ", {
                method: 'POST',
                form: {
                    token: access_token,
                    user: param['user_id']
                }
            }, (error, response, body) => {
                res.send(JSON.parse(body));
            })
        })
    })
})

app.listen(3000, () =>{
        console.log('HTTP Server(3000) is running.');
});

おわりに

OAuth認証はほぼ初めてだったので、実際にコード書くと流れがわかってよかったです。

あと、認証と認可って言葉難しいですよね。使い方間違ってたら教えてください。。。

参考

AWS CognitoにGoogleとYahooとLINEアカウントを連携させる - Qiita

SlackでOAuthを利用して BOT投稿 するための アクセストークン を取得する方法 - UTALI

SlackでOAuth2を利用したときのメモ - Qiita

オウム返し slack bot をぱっとつくる - Qiita

Ignore invalid self-signed ssl certificate in node.js with https.request? - Stack Overflow

61
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
61
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?