[日本語Alexa] アカウントリンク時のイベントでSNSを送ってみました

1 はじめに

CX事業本部の平内(SIN)です。

スキルイベントを処理することで、Echoデバイスなどから呼ばれたタイミング以外でもスキルとしての動作を実装することが可能です。

上記は、スキルが有効/無効化された時のイベントを処理しているものですが、今回は、アカウントリンクが有効にされたイベントを処理してみました。

アカウントリンクのイベントでは、アクセストークンも受け取れますので、OAuth2サーバから、リンクしたアカウントのユーザー情報等(scopeで指定された範囲内)を受け取ることも可能です。

今回は、サンプルとして、ユーザー情報(電話番号)を取得し、SNSを送ってみました。

2 SKILL_ACCOUNT_LINKEDの追加

アカウントリンクのイベントを処理するためには、スキルのマニフェストに定義する必要があります。

マニフェストを取得及び、更新するSMAPのコマンドは、以下のとおりです。

取得

$ ask api get-skill -s amzn1.ask.skill.xxxxxx-xxxxxx > skill.json

更新

$ ask api update-skill -s amzn1.ask.skill.xxxxxx-xxxxxx -f skill.json

マニフェストのevents.subscriptionsには、SKILL_ACCOUNT_LINKEDを追加します。なお、endpointは、有効なLambdaファンクションであれば、何でも良いのですが 、今回は、アカウントリンクの対象となっているスキルで受け取ることにしました。

"events": {
    "subscriptions": [
        {
            "eventName": "SKILL_ACCOUNT_LINKED"
        }
    ],
    "endpoint": {
        "uri": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:Handle-Alexa-account-linking-events"
    }
},

3 イベント時のリクエスト

先のマニフェストを設定した後、スキルのアカウントリンクを有効にすると、下記のリクエストが(Endpointをスキルにしているため)スキルに到着します。

リクエストのタイプは、AlexaSkillEvent.SkillAccountLinkedとなっており、context.System.user.accessTokenは、アカウントリンク後にスキルが受け取るトークンと同じです。

ちなみに、request.body.accessTokenというのもあるのですが、これが何に使えるのかよく分からないです。

{
    "version": "1.0",
    "context": {
        "System": {
            "application": {
                "applicationId": "amzn1.ask.skill.xxxxxx"
            },
            "user": {
                "userId": "amzn1.ask.account.xxxx",
                "accessToken": "xxxxxxx"
            },
            "apiEndpoint": "https://api.amazonalexa.com",
            "apiAccessToken": "xxxxxxxx"
        }
    },
    "request": {
        "type": "AlexaSkillEvent.SkillAccountLinked",
        "requestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
        "timestamp": "2019-09-07T21:05:47Z",
        "eventCreationTime": "2019-09-07T21:05:47Z",
        "eventPublishingTime": "2019-09-07T21:05:47Z",
        "body": {
            "accessToken": "xxxxxxxxx"
        }
    }
}

4 サンプル実装

サンプルとして、accessTokenを使用してOAuthサーバからユーザー情報(電話番号)を取得し、SNSを送っているコードは以下のとおりです。OAuth2は、Cognitoです。

// Alexa SDKのハンドラ形式で処理する
const SkillAccountLinkedHandler = {
    canHandle(h: Alexa.HandlerInput) {
        return (h.requestEnvelope.request.type === 'AlexaSkillEvent.SkillAccountLinked');
    },
    async handle(h: Alexa.HandlerInput) {

        const userInfo  = await getUserInfo(h.requestEnvelope.context.System.user.accessToken as string);
        console.log(userInfo.phone_number);
        const sns = new AWS.SNS();
        await sns.publish({
            Message: "ご利用ありがとうございます\(^o^)/",
            PhoneNumber: userInfo.phone_number as string
        }).promise();

        // 型を合わせるために記述しているが、レスポンスは必須ではない
        return h.responseBuilder.getResponse(); 
    }
};

async function getUserInfo(token: string): Promise<{phone_number:String}> {
    return new Promise((resolve,reject) => {
        var options = {
            url: `https://alexa-user-pool.auth.ap-northeast-1.amazoncognito.com/oauth2/userInfo`,
            headers: { Authorization: 'Bearer ' + token}
        }
        request(options, (error: any, response: any, body: any) => {
            if(error){
                reject(error);
            }
            if(response.statusCode != 200) {
                reject(`StatusCode: ${response.statusCode}`)
            }
            resolve(JSON.parse(body));
        })
    });
}

5 最後に

今回は、アカウントリンクが有効化された際のイベントを処理してみました。リンク先のアカウント情報も利用できるので、色々応用的に使えるかも知れません。

6 参考にさせて頂いたリンク


[Alexa] スキルイベントを使ってスキルが有効/無効化されたらSlackに通知してみる
Alexaスキルのスキルイベント

コメントは受け付けていません。