AWSLambdaからUserPoolの属性を変更

#はじめに
Cognitoのユーザ属性にカスタム属性として「セーブ数」を登録して、管理者が許可したらその属性を修正し、アプリ側でカスタム属性を取得したいなぁ…と思ったら案外めんどくさかった、という話。

#まとめると
・AWS管理コンソールから属性の値を登録することも更新することもできない（と思う）。
・でもAPIからなら普通に更新ができる。
・値も普通に取得できる。

#ユーザのカスタム属性の値を修正したいんですけど
ユーザを初期登録するときには設定できる。
でも修正ができない。
管理コンソールに修正するところがあるんじゃないか？と思って眺めても…ない。
ネットを調べてもない。
Userpool自体の初期登録の仕方なのか？と思ったがそうでもない様子。

#そもそもカスタム属性は初期登録時のみなのか？？
メソッド名に「adminUpdateUserAttributes」なんてのがあるんだから更新できるんじゃないの？
と思って、せめてAPI経由でも更新させてくれよーと思ったら…

[awsのフォーラム](https://forums.aws.amazon.com/thread.jspa?threadID=230275)にありました。

```js
var AWS = require('aws-sdk');
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
exports.handler = (event, context, callback) => {
var params = {
UserAttributes: [ / required /
{
Name: 'custom:attributename', / required /
Value: 'value'
},
/ more items /
],
UserPoolId: 'ap-southeast-2_abcdefghi', / required /
Username: 'username'/ required /
};
cognitoidentityserviceprovider.adminUpdateUserAttributes(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
};
```

なるほどできるんだなぁ…と思って、やってみた。
/required/
ってコメントは抜かないとエラーになるんだなぁ…

```js:index.js(lambda)
var AWS = require('aws-sdk');
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
exports.handler = (event, context, callback) => {
var params = {
    UserAttributes: [
    {
    Name: 'custom:SavePoint', 
    Value: '2'
    },
    ],
    UserPoolId: 'ap-northeast-1_hohohoho',
    Username: 'hoge'
};
cognitoidentityserviceprovider.adminUpdateUserAttributes(params, function(err, data) {
    if (err) console.log(err, err.stack); // an error occurred
    else console.log(data); // successful response
    });
};
```
これだけだとアクセス権とか大丈夫なのか？と思ったら案の定ロール定義が必要だった。
ロール定義するためにはポリシー定義が必要でした。
![無題.jpg](https://qiita-image-store.s3.amazonaws.com/0/219000/a2a127c3-c77e-4e99-643c-715b37f02268.jpeg)
必要なポリシーは「cognito User Pools」のみ。
そのポリシーと新しく作ったロールを関連付ける。
そして、上記関数のロールにする。

実行すると…案外素直に動きました。
カスタム属性はnumber型なのですが、valueの指定は''を付けるんだね。

![無題2.jpg](https://qiita-image-store.s3.amazonaws.com/0/219000/533ac1aa-4112-9a73-f576-7aea4ae2dd84.jpeg)

値が変わったことは画面から確認できる。
なお、もともと値が登録されてなくてもadminUpdateUserAttributesを使えば登録できる。

#値の取得
これもまた微妙に面倒…

[日本語で書かれたチュートリアル](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/tutorial-integrating-user-pools-javascript.html)があるのだが、なんだかわかりにくい。
結局[SDKのサンプル]
(https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html#getUser-property)をみて作成した。

```javascript:hoge.js(clientside)
AWS.config.update({
          accessKeyId: 'XXXXXXXXX',  //IAMのアクセスキーID
          secretAccessKey: 'YYYYYYY',  //アクセスキーID作成時のみ表示
          region:'ap-northeast-1',
          IdentityPoolId: 'ap-northeast-1:XX-XXXX-xxxx-xxxx-xx'
        });

（signin処理は省略：signin時にアクセストークン取得できる。）

var SavePoint = 0;
var cognitoSP = new AWS.CognitoIdentityServiceProvider({apiVersion: '2016-04-18'});


cognitoSP.getUser({AccessToken:data.AuthenticationResult.AccessToken},function(err,data){
  if(err) console.log(err,err.stack);
  else {
    data.UserAttributes.forEach(function(val,id,arary) {
      if (val.Name == 'custom:SavePoint') {
        SavePoint = val.Value;
      }
    });
  }
});
 ```
途中の「data.AuthenticationResult.AccessToken」にはアクセストークンを入れる必要がある。
アクセストークンはsignin時に取得できる。（ここでは途中端折ってる）
これでSavePointにcognitoのカスタム属性(custom:SavePoint)の値が入りました。

#最後に
案外簡単なのはわかったが、ここまで来るのに4時間ぐらいかかった。
値の変更を画面からでも追加、修正できるようになればもう少し簡単になるのだけど。