はじめに
Alexa センサー用のスマートホームスキルでChangeReport
をAlexaのイベントゲートウェイ
に送信する際に、ユーザーをAlexaで認証する必要がある。その認証で必要なトークンの取得方法からイベントゲートウェイへの送信方法の覚書。
前提
- Alexaスキル モデル:スマートホーム(センサー用)
- OAuthプロバイダー:LWA(Login with Amazon)
流れ
センサー用スマートホームスキルのエンドポイントのプロパティ値を変更した場合は必ずプロアクティブにChangeReport
イベントを送信する必要がある。
LWAからトークンを取得
トークンの有効期限は取得後60分。60分を超え、無効になったトークンを使用してリクエストを送信すると、401 Unauthorized
が返却され認証されない。そのため、有効期限が切れた場合は、前回取得したトークンに含まれるrefresh_token
を使用してトークンを再発行する必要がある。
新規リクエスト(初回)
一番最初にトークンを取得する場合のリクエスト。
AcceptGrant
ディレクティブのcode
フィールドの値を使用して、LWAにアクセストークンリクエストを送信し、アクセストークンを取得する。
POST /auth/o2/token HTTP/l.l
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded;Accept-Charset=UTF-8
grant_type=authorization_code&code=SplxlOBezQQYbYS6WxSbIA&client_id=【AlexaクライアントID:】&client_secret=【Alexaクライアントシークレット:】
パラメータ
No. | 項目 | 値 | 備考 |
---|---|---|---|
1 | grant_type | authorization_code | 固定値 |
2 | code | SRgccpEPdzDayxqHFsma | AcceptGrantから取得 |
3 | client_id | 【AlexaクライアントID:】 | alexa developer console(※)から取得 |
4 | client_secret | 【Alexaクライアントシークレット:】 | alexa developer console(※)から取得 |
※alexa developer console -> 対象スキル -> ビルド -> アクセス権限 -> Alexaスキルメッセージング
レスポンス
{
"access_token":"Atza_IwEBI...Fq2w8uYFfE",
"refresh_token":"Atzr_IwEBI...f6ohOBg3ig",
"token_type": "bearer",
"expires_in": 3600
}
※code値の取得方法
code値
はAcceptGrant
レスポンスから取得する。
Alexaアプリを開き、対象のスマートホームスキルを有効にして、スキルとアカウントをリンクする。アカウントリンクが成功すると、AcceptGrant
がスキルに送信されるので、CloudWatchログにAcceptGrant
を出力させて、directive.payload.grant.code
を取得する。Lambda関数を作成してAcceptGrant
を 取得する方法はこちらに記載。
※もう一度AcceptGrant
を送信したい場合は、Alexaアプリで対象スキルをスキルを無効にする
にして、再有効化する。有効化時にアカウントリンクを設定するとAcceptGrant
が送信される。
{
"directive": {
"header": {
"namespace": "Alexa.Authorization",
"name": "AcceptGrant",
"messageId": "873c203b-833c-46a5-8ed6-9c7d2444df35",
"payloadVersion": "3"
},
"payload": {
"grant": {
"type": "OAuth2.AuthorizationCode",
"code": "SRgccpEPdzDayxqHFsma" ← これ
},
"grantee": {
"type": "BearerToken",
"token": "Atza_IwEBI...z71DaTIJnI"
}
}
}
}
curlでaccess_tokenを取得してみる
Windowsのコマンドプロンプトで以下を実行する。
c:\> curl -i -X POST -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" -d "grant_type=authorization_code&code=<directive.payload.grant.code>&client_id=<AlexaクライアントID>&client_secret=<Alexaクライアントシークレット>" https://api.amazon.com/auth/o2/token
こんな感じで結果が返ってくる。
HTTP/1.1 200 OK
Server: Server
Date: Wed, 12 Jan 2022 08:59:55 GMT
Content-Type: application/json;charset=UTF-8
Content-Length: 656
Connection: keep-alive
x-amz-rid: H3JRCKNG4SD4H96ZZ41V
x-amzn-RequestId: d22f0700-c8a4-43e1-adbe-664b59ec80ba
X-Amz-Date: Wed, 12 Jan 2022 08:59:55 GMT
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Vary: Content-Type,Accept-Encoding,X-Amzn-CDN-Cache,X-Amzn-AX-Treatment,User-Agent
Permissions-Policy: interest-cohort=()
{"access_token":"Atza|IwEBIDtWO-tfB5kMY5Evs-iDOIKVysDoxdqdak8F15dwAdZgNCtC-a8TXsr8Y3Pzjn1TT6riulDI8KseIPgqZoRe8AHkqGVLhO2tcj3_OL-RCV2ZEk9KkKukBo7YNmOHqZhbs1z-VBqNzBaeVlH8q2liVA8FYy8E8Jir6jmvVv3QX6g4NvOYxB9TYDeRlBEg_XvfECbn5cjbXEc7hhgdffDhJnLVLLfii_DnhVr7kKInuaXO_jEZ2ZIiVEHVqA5LwSPbZeXL8KbAnkP_Jf33Rd83K_eR","refresh_token":"Atzr|IwEBILi1ETOk-rWAqVRVI-ClT3Rf212dSv5QM3ohHQBqMz4X4D80Iojh8BaSc-gOsppXeDNAHvxuWTIP_l80JbaLZ0SwicDLYqe2av_NNO5pIpE_hzDccntZ_FUD-ZGi4Xz5TrZAnaVz4CIonATb8ei9fG01lqC5vh3UGkxrgGpkXLILZT_F6ZujMU7qoSPQGSCPwohrZAr9vo4J9xaXCnas_kOBvRmES4Ji59JaRcIKVvRLpU94h_3Thm7Jn5WURh_gFFFb6wxgJwPhnmnsxFKMYSmb","token_type":"bearer","expires_in":3600}
更新リクエスト(2回目以降)
2回目以降のトークン取得。URLは変わってないが、リクエストのパラメータが変わっているので注意。code
ではなくrefresh_token
を使用する。
POST /auth/o2/token HTTP/l.l
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded;Accept-Charset=UTF-8
grant_type=refresh_token&refresh_token=Atzr_IwEBI...f6ohOBg3ig&client_id=【AlexaクライアントID:】&client_secret=【Alexaクライアントシークレット:】
パラメータ
No. | 項目 | 値 | 備考 |
---|---|---|---|
1 | grant_type | refresh_token | 固定値 |
2 | refresh_token | Atzr_IwEBI...f6ohOBg3ig | |
3 | client_id | 【AlexaクライアントID:】 | alexa developer console(※)から取得 |
4 | client_secret | 【Alexaクライアントシークレット:】 | alexa developer console(※)から取得 |
※alexa developer console -> 対象スキル -> ビルド -> アクセス権限 -> Alexaスキルメッセージング
レスポンス
{
"access_token":"Atza_IwEBI...MMbdgEWYWI",
"refresh_token":"Atzr_IwEBI...f6ohOBg3ig",
"token_type": "bearer",
"expires_in": 3600
}
curlでrefresh_tokenを取得してみる
Windowsのコマンドプロンプトで以下を実行する。
c:\> curl -i -X POST -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" -d "grant_type=refresh_token&refresh_token=<1回目で取得したrefresh_token>&client_id=<AlexaクライアントID>&client_secret=<Alexaクライアントシークレット>" https://api.amazon.com/auth/o2/token
こんな感じで結果が返ってくる。
HTTP/1.1 200 OK
Server: Server
Date: Wed, 12 Jan 2022 08:42:45 GMT
Content-Type: application/json;charset=UTF-8
Content-Length: 678
Connection: keep-alive
x-amz-rid: 1ME24VEDQSZAW9ZF13D1
x-amzn-RequestId: fb439232-7e44-466c-886b-bd55ca9ddace
X-Amz-Date: Wed, 12 Jan 2022 08:42:45 GMT
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Vary: Content-Type,Accept-Encoding,X-Amzn-CDN-Cache,X-Amzn-AX-Treatment,User-Agent
Permissions-Policy: interest-cohort=()
{"access_token":"Atza|IwEBIF1cVmtHDvsBx8tnufdj97glJDvZyTBDM1ZMLXWQHSN1nlJSFJ-YTDomMV6vIGqHa7_lQ1nzHvKsg_PLFjVRq21_d_KFP_E8jb48kz_MctvPZNOsHcJCEAo7swbG0l5pyEUaCpKyDDU3Qlh8kxns_9PMj_ehTqQbhxLC0__RmJzRZuxkgt6w9z-qa7y77V5gdZxf1VIwkbwEqGY9wal4kpI5i4THtNawLQzmtlFhVNkP5RtOvSfNsspMHDG5huF7NvlBYc9XtRMEU8GgKwLWMfmILU18-tN6s50vC1yzbnOUQA","refresh_token":"Atzr|IwEBICo1PeLUZFMDzi_al8nCxH5hQYDky_6nI9Tmmvl-NJ4u7xO0-fkMr0rxSGJPOmVTm8-0AVMDmglzCE0ebnt8oUgo1BBXTY2gy5U1inxHx-o8-oO5UzWXIfHCbprXPncLQdF_ROeMHfOpeCNm31vooVjzpNFoNMCB3Ww64ROFSQlM1duUWqb2OLZRFgE2G_OuYNczaPoeDhHCoT9ee8UwvHfaWXn-Iccw2rfmhBPd9m_uVzu_R8dxJ-4rO8bzSvhOge6IyTGfMFRWwMMPm5bGBNVb","token_type":"bearer","expires_in":3600}
ChangeReportを作成
event.endpoint.scope.toke
に上記で取得した access_token
を設定する。
endpointId
などに、作成したスマートホームスキルの情報を設定する。
{
"context": {},
"event": {
"header": {
"messageId": "tkr-123-def-456",
"namespace": "Alexa",
"name": "ChangeReport",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type":"BearerToken",
"token":"Atza_IwEBI...MMbdgEWYWI" ← access_token
},
"endpointId" : "sensor-001"
},
"payload": {
"change": {
"cause": {
"type": "PHYSICAL_INTERACTION"
},
"properties": [
{
"namespace": "Alexa.MotionSensor",
"name": "detectionState",
"value": "DETECTED",
"timeOfSample": "2020-03-22T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
}
]
}
}
}
}
イベントゲートウェイに送信
スマートホームスキルの言語を英語で作成したとしても、日本のAmazonアカウントを使用している場合は、エンドポイントに極東を使用する。
エンドポイント
- 北米:https://api.amazonalexa.com/v3/events
- ヨーロッパ:https://api.eu.amazonalexa.com/v3/events
- 極東:https://api.fe.amazonalexa.com/v3/events
リクエスト
HTTPヘッダーAuthorization
のBearer
の後に半角スペースを空け、上記で取得した access_token
を設定する。
POST /v3/events HTTP/1.1
Host: api.fe.amazonalexa.com
Authorization: Bearer Atza_IwEBI...MMbdgEWYWI
Content-Type: application/json
{
"context": {},
"event": {
"header": {
"messageId": "tkr-123-def-456",
"namespace": "Alexa",
"name": "ChangeReport",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type":"BearerToken",
"token":"Atza_IwEBI...MMbdgEWYWI"
},
"endpointId" : "sensor-001"
},
"payload": {
"change": {
"cause": {
"type": "PHYSICAL_INTERACTION"
},
"properties": [
{
"namespace": "Alexa.MotionSensor",
"name": "detectionState",
"value": "DETECTED",
"timeOfSample": "2020-03-22T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
}
]
}
}
}
}
レスポンス(成功)
202 Accepted
が返却されれば成功。
※何も返却されない。
レスポンス(失敗)
トークンの有効期限が切れている場合は、401 Unauthorized
が返却されるので、トークンを更新した後、再リクエストする。他のエラーの場合はマニュアルを参照し対応する。
{
"header": {
"namespace": "System",
"name": "Exception",
"messageId": "fddd317c-2acf-4cba-a88e-fc0433385be8"
},
"payload": {
"code": "INVALID_ACCESS_TOKEN_EXCEPTION",
"description": "Access token is not valid."
}
}
おわりに
定型アクションで、スマートホーム(センサー)をトリガーにして、Alexaがアクションするところまで確認した。
今回は、センサーデバイスからではなくブラウザを使用して、ベントゲートウェイへChengeReport
リクエストを送信した。
記載している内容は、2020年3月30日時点での情報。変更されている可能性があるので注意。
参考
- スマートホームスキルの作成手順(※Amazon公式サイト)
- センサー用のスマートホームスキルを作成する(※Amazon公式サイト)
- アクセス権限を設定してAlexaへのユーザー認証を実現する(※Amazon公式サイト)