AWS Amplify フレームワークの使い方Part2〜Auth実践編〜

# はじめに
AmplifyのAuth関係で提供されているAPIについて解説していきます。まだ未検証のAPIも多く存在していますが、下記の内容がわかれば、ログインフォームくらいは実装ができると思います。

# Auth API一覧
APIの一覧をまとめています。基本的には、`import { Auth } from 'aws-amplify'`をインポートしておいて、 `Auth.〇〇`という形で使います。基本的に非同期処理で行いたいので、 `async`をつけた関数の中で、`await`をすべてつけて実行しています。

## ログイン周り系API
### signUp
```javascript
const userData = await Auth.signUp(
  userId,    // 一意なID、すでに使われている場合はエラーになります
  passward,  // cognitoで定めたパスワードポリシーに則ったパスワード
  email      // メールアドレス 
)
```
サインアップについても基本的には1行実装です。たったこれだけです。メールアドレスの検証を設定していると認証コードが登録したメールアドレスに送信されます。

### confirmSignUp
```javascript
await Auth.confirmSignUp(
  userId,         // singUp時に入力したuserId
  verificationCode // 認証コード
)
```
signUp時に届いた認証コードを入力し、メールアドレスの検証を行います。

### resendSignUp
```javascript
await Auth.resendSignUp(
  userId  // singUp時に入力したuserId
)
```
認証コードの再送信をしてくれます。

### singIn
```javascript
const userData = await Auth.signIn(userId, passward)
```
返り値(userData)に、ログイン情報が入っています。この返り値には、usernameや二段階認証の設定有無の情報が含まれています。二段階認証(SMS認証)を設定している場合は、認証コードが送信されます。

### confirmSignIn
```javascript
const userData = await Auth.confirmSignIn(
  user,              // signInの返り値のuserData
  verificationCode,  // 認証コード
  user.challengeName // 自身が設定している認証設定 'SMS' or 'TOTP'
)
```
SMS認証やTOTP認証を設定している場合は、このAPIを叩いて初めて、サインインが完了します。

### federatedSignIn
```javascript
Auth.federatedSignIn({ provider: 'Google' })
```
各種設定は必要ですが、たったこれだけでソーシャルログインが可能になります。

### forgotPassword
```javascript
await Auth.forgotPassword(userId)
```
これだけで、登録しているメールアドレスにパスワードの再設定の認証コードを送信してくれます。

### forgotPasswordSubmit
```javascript
await Auth.forgotPasswordSubmit(
  userId,
  verificationCode, // 認証コード
  newPassword       // 新しいパスワード
)
```
届いた認証コードと新しいパスワードを渡せば、これだけでパスワードの更新は完了です。

### signOut
```javascript
await Auth.signOut()
```
ログアウトは至ってシンプルです。

## Cognito情報変更系API
### changePassword
```javascript
const user = await Auth.currentAuthenticatedUser() // ログイン中のユーザー情報
await Auth.changePassword(
  user, 
  nowPassword, // 現在のパスワード
  newPassword  // 新しいパスワード
)
```
これだけでパスワードの更新が行えます。

### updateUserAttributes
```javascript
const user = await Auth.currentAuthenticatedUser()
await Auth.updateUserAttributes(
  user,
  {
    // 更新したい情報を渡す 
    email: newEmail, // 新しいメールアドレス
    phone_number: newPhoneNumber // 新しい電話番号
  }
)
```
Cognitoに保存している情報(emailやphone_numberなど)を更新ができます。

### verifyCurrentUserAttributeSubmit
```javascript
await Auth.verifyCurrentUserAttributeSubmit(
  'email', // メールアドレスまたは電話番号
  verificationCode // 認証コード
)
```
メールアドレスを変更した際に、認証コードが届くので、入力してそのメールアドレスを有効にします。

### verifyCurrentUserAttribute(2020/4/27追記、2021/3/6修正)
```javascript
await Auth.verifyCurrentUserAttribute(
 'email' // メールアドレスまたは電話番号
)
```
上記の認証コードの再送信をしてくれます。


## ログイン情報取得系API
### currentAuthenticatedUser
```javascript
const user = await Auth.currentAuthenticatedUser()
```
ログイン中のユーザー情報が取得できます。

### currentSession
```javascript
const user = await Auth.currentSession()
```
ログイン中のユーザーのセッション情報が取得できます。

### currentCredentials
```javascript
const user = await Auth.currentCredentials()
```
identityIdを習得したい時に利用しました。`user.identityId`で取得ができます。

### currentUserCredentials, currentUserInfo
```javascript
const user = await Auth.currentUserCredentials()
const user = await Auth.currentUserInfo()
```
明確に違いがあるAPIなんだと思いますが、現状特に活躍はしていません。同じようにログイン車の情報が取得？できます。このあたりも明確にわかるとより細かい設定ができるのではないかと思います。

### currentUserPoolUser
```javascript
const user = await Auth.currentUserPoolUser(user)
```
こちらも細かい違いはわかりませんが、ログイン中のユーザー情報にプラスでUserPoolのIDなどのプラスアルファの情報が取得できます。使い所は不明です。

## 2段階認証系API
### getPreferredMFA
```javascript
const user = await Auth.currentAuthenticatedUser()
const state = await Auth.getPreferredMFA(
  user, 
  { bypassCache: false } // おまじない
)
// state = 
//  'SMS_MFA'  => SMS認証
//  'SOFTWARE_TOKEN_MFA' => TOTP認証
//  'NOMFA' => ２段階認証未設定
```
現在の2段階認証の設定情報を取得します。

### setPreferredMFA
```javascript
const user = await Auth.currentAuthenticatedUser()
await Auth.setPreferredMFA(
  user,
  authType // 'SMS' or 'TOTP' or 'NOMFA'
)
```
二段階認証の設定を変更できます。`NOMFA`にすると二段階認証がOFFになります。

### setupTOTP
```javascript
const data = await Auth.setupTOTP(
  userData // signIn時の返り値のuserData
)
token = 'otpauth://totp/AWSCognito:' + userId + '?secret=' + data + '&issuer=サイト名'
```
このtokenをQRコードの生成コンポーネントに渡すことで、TOTP認証のQRコードを生成することができます。あとはこのQRコードを読み込んで、アプリに表示されている認証コードをconfirmSignUpで入力すればログインができます。 `issuer=〇〇`の部分が認証コードアプリに表示される名前になります。

トラップとして、二段階認証をTOTPで設定している際に、`setupTOTP`を実行し`verifyTotpToken`で有効にする前に設定をやめてしまうと、無効なTOTPという扱いになり、TOTP認証ができなくなります。(二段階認証が有効というUI表示なのに、実際はTOTP認証ができないという事象が生まれる)
回避策として、`setPreferredMFA(user, 'NOMFA')`で二段階認証をOFFにしてから、`setupTOTP`実行するようにしています。
まだ、公式からもこのバグに対する回答は得られていない状態のようです。以下のissuesが解決されることを祈ります。
https://github.com/aws-amplify/amplify-js/issues/1226

### verifyTotpToken
```javascript
// ログインユーザーの認証情報取得
const user = await Auth.currentAuthenticatedUser()
// QRコードを読み込んだあとに表示される認証コードをstring化
const _verificationCode = this.verificationCode.toString()
// tokenの検証 => 正しければ有効
await Auth.verifyTotpToken(user, _verificationCode)
// tokenが有効な状態で初めてTOTP
await Auth.setPreferredMFA(user, 'TOTP')
```
二段階認証をTOTPに変更する場合は、`setPreferredMFA`を行う前にこの`verifyTotpToken`でのtokenの検証が必要です。そして、`verifyTotpToken`に渡す認証コードはstring型でなければならないという罠があるため、認証コードをstring型に変換しています。

### disableSMS,  enableSMS
```javascript
const user = await Auth.currentAuthenticatedUser()
await Auth.disableSMS(user) // SMSを無効
await Auth.enableSMS(user) // SMSを有効
```
SMS認証の切り替えができるみたいなのですが、いまいちまだ動作が明確にわかっていないため、SMS認証を実装するためには要調査となっています。


## サインアップ管理系API
### completeNewPassword
```javascript
await Auth.completeNewPassword(
  user, // signInの返り値のuserData
  password // 変更する新しいパスワード
)
```
Cognitoでユーザーを作成した際、仮パスワードを変更するのに使います。

### verifiedContact
```javascript
const data = await Auth.verifiedContact(
  user, // signInの返り値のuserData
)

/* 返り値
{
  verified: {
    email: 'xxxx@example.com'
  },
  unverified: {}
}
*/
```
電話番号またはEmailが確認済みかの判定して、電話番号/Emailが返り値で返ってきます。


## 未解明/未調査のAPI
- configure
- essentialCredentials
- getModuleName
- getMFAOptions
- sendCustomChallengeAnswer
- userAttributes
- userSession
- verifyUserAttribute
- verifyUserAttributeSubmit

# おわりに
未解明・未調査のAPIも使いこなせるようになるともっとAuthの可能性が広がると思います。ぜひ、ご存知なAPIがありましたら、コメントをお願いいたします。

# 参考記事
- [Amplify Authentication 公式ドキュメント](https://aws-amplify.github.io/docs/js/authentication) 
- [Amplify Authentication 公式API一覧](https://aws-amplify.github.io/amplify-js/api/classes/authclass.html) 

# 関連記事
[AWS amplify フレームワークの使い方Part1〜Auth設定編〜](https://qiita.com/too/items/fc961283dcbef3aafdeb)
[AWS Amplify フレームワークの使い方Part3〜API設定編〜](https://qiita.com/too/items/c0ce14d16772b9f71223)
[AWS Amplify フレームワークの使い方Part4〜API実践編〜](https://qiita.com/too/items/f9078803ea394c35df7d)
[AWS Amplify フレームワークの使い方Part5〜GraphQL Transform @model編〜](https://qiita.com/too/items/ab6b313da9f9e34be4a7)
[AWS Amplify フレームワークの使い方Part6〜GraphQL Transform @auth編〜]
(https://qiita.com/too/items/fae2879ea36f00c3ae10)
[AWS Amplify フレームワークの使い方Part7〜GraphQL Transform @key編〜]
(https://qiita.com/too/items/cb1dfb4f44536a3e9855)
[AWS Amplify フレームワークの使い方Part8〜GraphQL Transform @connection編〜](https://qiita.com/too/items/c77f1e5487d2497b5061)
[AWS Amplify フレームワークの使い方Part9〜Function 基礎編〜](https://qiita.com/too/items/d2732b3ec625011f4567)
[AWS Amplify フレームワークの使い方Part10〜Storage編〜](https://qiita.com/too/items/361bc10b6d27f133e9f8)
[AWS Amplify フレームワークの使い方Part11〜Function 権限管理編〜](https://qiita.com/too/items/b34cbfd7e96a01e33f23)
[AWS Amplify フレームワークの使い方Part12〜ENV編〜](https://qiita.com/too/items/5c1e28cf95fc6229547e)
[AWS Amplify フレームワークの使い方Part13〜Auth 設定更新編〜]
(https://qiita.com/too/items/52f35860bcb5bdf5e667)
[AWS Amplify フレームワークの使い方Part14〜Lambda レイヤー編〜]
(https://qiita.com/too/items/54de781085bd9a3a66d0)