AWSとTwitter API v2を利用して、自動ツイートシステムを作る方法
Twitter APIのV2への移行により、APIの認証フローやトークンの管理をAWS上で行う方法が紹介されています。SSMリソースをIaCで定義することで、OAuthクライアントシークレットを取得する方法、ツイートのリクエスト内容についての解説、Secrets Storeの使用方法が紹介されています。個人利用で廉価に利用したい場合、Systems Manager Parameter Storeを利用し、GetParameterCommandとPutParameterCommandを利用した処理をすることが推奨されています。また、2つのクラスを利用するOAuthで認証してAPIを利用する方法も紹介されています。
目次
Twitter APiがV2に変わりましたが、少量のツイートであれば引き続き無料で使うことができます。
APIの認証フローやトークンの管理をAWS上で行う方法を簡単にまとめました。
紹介しないこと
この辺りの内容は今回紹介しません。
generateAuthURL
やrequestAccessToken
を利用した、OAuthクライアントシークレットの取得方法- SSMリソースをIaCで定義する方法
- ツイートのリクエスト内容の解説
Systems ManagerのParameter Storeで手軽に管理する
Secrets Storeを使う方が良いとは思いますが、個人利用で廉価に使いたいため、Systems Manager Parameter Storeを利用します。
使うコマンドは、GetParameterCommand
とPutParameterCommand
の二つで良さそうです。
serverless.ts
の場合は、こんな感じでIAMロールを設定しましょう。
iam: {
role: {
statements: [{
Effect: 'Allow',
Action: [
'ssm:GetParameter',
'ssm:PutParameter'
],
Resource: [
"arn:aws:ssm:us-west-2:123456:parameter/TWITTER_OAUTH*",
"arn:aws:ssm:us-west-2:123456:parameter/TWITTER_TOKEN*"
]
}]
}
}
}
取得と更新処理は、次のようなクラスを作りました。
実際にはTypeScriptの型が付いていますが、抽象化させている部分が説明には冗長なので削りました。
import { GetParameterCommand, PutParameterCommand, SSMClient } from "@aws-sdk/client-ssm";
export class SSMSecretManager{
private readonly client
constructor(config) {
this.client = new SSMClient(config)
}
public async getSecretsByName(keyName) {
const getParameterCommand = new GetParameterCommand({
Name: keyName,
WithDecryption: true
})
const response = await this.client.send(getParameterCommand)
if (!response.Parameter || !response.Parameter.Value) {
return null;
}
const value = JSON.parse(response.Parameter.Value)
return value
}
public async updateSecrets(keyName, value) {
const updateSecretCommand = new PutParameterCommand({
Name: keyName,
Overwrite: true,
Type: "SecureString",
DataType: 'text',
Value: JSON.stringify(value),
})
await this.client.send(updateSecretCommand)
}
}
2つの秘密情報を取得する
SSMには2つのデータを保存しています。
1つはOAuth用のクライアントシークレットなどの情報、もう1つはアクセストークン・リフレッシュトークンなどです。
const client = new SSMSecretManager({ region: 'us-west-2' })
const clientSecrets = await client.getSecretsByName('TWITTER_OAUTH_CLIENT_SECRETS')
const token = await client.getSecretsByName('TWITTER_TOKEN')
また、取得したトークンが期限切れしている場合は、更新処理が必要です。
const diffFromTheExpiresAt = new Date(token.expires_at).getTime() - new Date().getTime()
if (diffFromTheExpiresAt < 0) {
// Refresh access token
}
Twitter API v2では、2つのクラスを利用する
OAuthで認証してAPIを利用するため、auth.OAuth2User
とClient
の2クラスを利用しました。
const authClient = new auth.OAuth2User({
...clientSecrets,
token,
})
const client = new Client(authClient)
クライアントシークレットとアクセストークンの両方を利用しますので、SSMの戻り値を合成して利用しましょう。
アクセストークンを更新する場合、更新後のレスポンスをtoken
に再設定します。
const newToken = await authClient.refreshAccessToken()
const client = new Client(new auth.OAuth2User({
...clientSecrets,
token: newToken.token,
}))
SSMでリフレッシュしたアクセストークンを保存する
リフレッシュすると、以前のアクセストークンは利用できません。SSMの値も更新しましょう。
SSMのパラメーターストアには「更新操作」はなく、「上書き」になることに注意が必要です。
上のサンプルコードを再掲しますが、暗号化などの設定も明示的に行うことをお勧めします。
public async updateSecrets(keyName, value) {
const updateSecretCommand = new PutParameterCommand({
Name: keyName,
Overwrite: true,
Type: "SecureString",
DataType: 'text',
Value: JSON.stringify(value),
})
await this.client.send(updateSecretCommand)
}