【AWS】CognitoのJWTトークン検証処理時間を比較

# 比較内容

## 比較パターン

- `aws-jwt-verify` を使用し、初回インスタンス生成
- `aws-jwt-verify` を使用し、呼び出しごとにインスタンス生成
- `jsonwebtoken` を使用

## 比較コード

### 共通コード

検証したいパターン以外はコメントアウトして使用する。

```js
console.time('処理時間');
// リクエストヘッダーからアクセストークンを取得
const token = req.headers.authorization?.split(' ')[1];

// アクセストークン検証
try {
  /** 初回インスタンス生成 */
  await verifier.verify(token);

  /** jsonwebtokenを使用 */
  await verify(token);

  /** 呼び出しごとにインスタンス生成 */
  await verifyJwtToken(token);

} catch (error) {
  console.error(error);
}

console.timeEnd('処理時間');
```

### 初回インスタンス生成

以下をnode起動時に実行する。

```js
const { CognitoJwtVerifier } = require('aws-jwt-verify');

require('dotenv').config();

const { USER_POOL_ID, TOKEN_USE, CLIENT_ID } = process.env;

// JWT検証器生成
const verifier = CognitoJwtVerifier.create({
  userPoolId: USER_POOL_ID,
  tokenUse: TOKEN_USE,
  clientId: CLIENT_ID,
});
```

### 呼び出しごとにインスタンス生成

下記のメソッドを使用する。

```js
const { CognitoJwtVerifier } = require('aws-jwt-verify');

require('dotenv').config();

const { USER_POOL_ID, TOKEN_USE, CLIENT_ID } = process.env;

const verifyJwtToken = async (token) => {
  const verifier = CognitoJwtVerifier.create({
    userPoolId: USER_POOL_ID,
    tokenUse: TOKEN_USE,
    clientId: CLIENT_ID,
  });

  return verifier.verify(token);
};

module.exports = { verifyJwtToken };
```

### jsonwebtoken を使用

下記のメソッドを使用する。

```js
const jwksClient = require('jwks-rsa');
const jwt = require('jsonwebtoken');

require('dotenv').config();

const { JWKS_URI } = process.env;

const client = jwksClient({
  jwksUri: JWKS_URI,
});

function getKey(kid, callback) {
  client.getSigningKey(kid.kid, (err, key) => {
    if (err) {
      return callback(err);
    }
    // 公開鍵を取得
    const signingKey = key.getPublicKey();
    callback(null, signingKey);
  });
}

function verify(token) {
  return new Promise((resolve, reject) => {
    jwt.verify(token, getKey, (err, decoded) => {
      if (err) {
        // 検証が失敗した場合、Promiseをrejectし、エラーを渡す
        reject(err);
      } else {
        // 検証が成功した場合、Promiseをresolveし、デコードされた結果を渡す
        resolve(decoded);
      }
    });
  });
}

module.exports = { verify };

```

# 比較結果

※単位は ms

- 実施結果

| トークン検証回数 | 初回インスタンス生成 | 呼び出しごとにインスタンス生成 | jsonwebtokenを使用 |
|------------------|----------------------|-------------------------------|-------------------|
| 1                | 115.187              | 131.139                       | 115.454           |
| 2                | 0.321                | 24.542                        | 0.927             |
| 3                | 0.323                | 23.391                        | 0.718             |
| 4                | 0.286                | 24.584                        | 0.621             |
| 5                | 0.304                | 28.688                        | 0.872             |
| 6                | 0.328                | 24.454                        | 1.11              |
| 7                | 0.266                | 23.433                        | 0.655             |
| 8                | 0.262                | 24.474                        | 0.615             |
| 9                | 0.361                | 26.168                        | 0.801             |
| 10               | 0.532                | 23.621                        | 0.634             |

- 平均と正規化

| トークン検証回数 | 初回インスタンス生成 | 呼び出しごとにインスタンス生成 | jsonwebtokenを使用 |
|------------------|----------------------|-------------------------------|-------------------|
|2回目～10回目の平均 |0.331	              |24.817                         |0.773              |
|正規化             |1                     |74.976                         |2.335              |

![JWTトークン検証処理時間.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/63b98dca-2568-bae3-e7b5-6b004350a1f6.png)

# 結論

- いずれも 1 回目はインスタンス生成のため 100ms 以上かかる
- `aws-jwt-verify` が早い
- 毎回インスタンス生成してはいけない

# 参考

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html

https://github.com/awslabs/aws-jwt-verify

https://github.com/auth0/node-jsonwebtoken