screenshot

其實本來是想要試用Twitter API 2.0的,但是要開啟新專案的時候被提示要先進行電話認證,所以只好先回來寫舊版本的筆記。 之所以舊版本不用電話認證的原因是在需要進行認證前就申請過了。

首先要去開發者後台把需要的keysecret複製出來,接著建立個setting.json把它們放進去:

{
    "key" : "",
    "secret" : "",
    "callback" : "http://127.0.0.1:3000/twitter/callback"
}

callback的值會是晚點會建立的API位置,路徑基本上應該要跟後台的設定一樣。

然後準備好package.json

{
  "name": "example-twitter-oauth10a",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "express": "^4.18.1",
    "express-session": "^1.17.3",
    "oauth": "^0.9.15",
    "twitter": "^1.7.1"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

接著就是index.js了:

const setting = require('./setting.json'); // key , secret , callback

const oauth = require('oauth');

const oa = new oauth.OAuth(
    'https://twitter.com/oauth/request_token',
    'https://twitter.com/oauth/access_token',
    setting.key,
    setting.secret,
    '1.0a',
    setting.callback,
    'HMAC-SHA1');

////

const express = require('express');
const session = require('express-session');

const secret = 'TEST_twitter_OAUTH_1.0a';

const app = express();

////

app.use(session({ secret }));

app.listen(3000, () => console.log('server port: 3000'));

////

app.get('/', (req, res) => {
    res.send(`<html><head></head><body><a href="/twitter/auth">login</a></body></html>`);
})

app.get('/done', (req, res) => {
    let at = req.session.oauthAccessToken;
    res.send(`<html><head></head><body><h1>Access token</h1><p>${at}</p></body></html>`);
})

app.get('/twitter/auth', async (req, res) => {
    const method = 'authenticate';
    const { requestToken, requestTokenSecret } = await getRequestToken();

    req.session = req.session || {};
    req.session.requestToken = requestToken;
    req.session.requestTokenSecret = requestTokenSecret;

    const authUrl = `https://api.twitter.com/oauth/${method}?oauth_token=${requestToken}`;

    console.log(`redirect to: ${authUrl}`);
    res.redirect(authUrl);
})

app.get('/twitter/callback', async (req, res) => {
    const { requestToken, requestTokenSecret } = req.session;
    const { oauth_verifier: verifier } = req.query;

    const { accessToken, accessTokenSecret } = await getAccessToken(requestToken, requestTokenSecret, verifier);

    req.session.oauthAccessToken = accessToken;

    console.log(`accessToken: ${accessToken} , accessTokenSecret: ${accessTokenSecret}`);

    //sendTweet(accessToken,accessTokenSecret , 'test it.');

    req.session.save(() => {
        res.redirect('/done');
    });
})

////

async function getRequestToken() {
    return new Promise((resolve, reject) => {
        oa.getOAuthRequestToken(
            (error, requestToken, requestTokenSecret) => {
                return error
                    ? reject(new Error('getRequestToken failed'))
                    : resolve({ requestToken, requestTokenSecret });
            })
    })
}

async function getAccessToken(requestToken, requestTokenSecret, verifier) {
    return new Promise((resolve, reject) => {
        oa.getOAuthAccessToken(
            requestToken,
            requestTokenSecret,
            verifier,
            (error, accessToken, accessTokenSecret) => {
                return error
                    ? reject(new Error('getAccessToken failed'))
                    : resolve({ accessToken, accessTokenSecret });
            })
    })
}

function sendTweet(accessToken, accessTokenSecret, status) {
    const Twitter = require('twitter');
    const twi = new Twitter({
        'consumer_key': setting.key,
        'consumer_secret': setting.secret,
        'access_token_key': accessToken,
        'access_token_secret': accessTokenSecret
    });

    const data = {
        status
    };

    twi.post('statuses/update', data, (error) => {
        if (error) {
            console.log(error);
        } else {
            console.log('tweet send.')
        }
    })
}

這邊寫了四支HTTP GET API

  • /

首頁只有一個超連結,點擊後就進行認證。

  • /done

流程跑完取得token後會轉到該頁面並印出token
正常不應該把它印出來,單純只是因為是本機測試為了方便。

  • /twitter/auth

首頁的超連結會呼叫該API,取得request token後會轉至twitter官方確認頁面讓使用者確認。

  • /twitter/callback

使用者點選確認連結後,twitter就會重導向到這支API來。
最後取得到需要的token放到session完就轉到/done頁面顯示。

拿到使用者的token後就可以用它們來呼叫twitter api了。


最後補上dockerfile

FROM node:18-alpine

RUN apk add --no-cache \
    nodejs

WORKDIR /app

COPY [ "package.json" , "index.js" , "setting.json" , "/app/" ]

RUN npm install
RUN npm install -g nodemon

EXPOSE 3000

CMD [ "nodemon", "index.js" ]

產生image

docker build -t example-twitter-oauth . --no-cache

最後執行:

docker run -itd -p 3000:3000 example-twitter-oauth

最後,到底要不要跑電話認證呢?其實也沒什麼,但就是有點抗拒啊⋯⋯