[Node.js / TypeScript] Amazon CognitoのJWTをデコードする、JWTを作成してテストする

2022.05.21

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、Node.jsとTypeScriptで、Amazon CognitoのJWTのデコード、およびJWTを作成してテストする方法を確認してみました。

※JWTのVerify(検証)は本記事では試しません。

やってみた

環境

  • typescript@3.9.10
  • node v14.17.0

インストール

JWTのデコードにはjwt-decodeを使用します。Auth0社が提供するパッケージです。

$ npm i jwt-decode

テスト用のJWTの作成にはjsonwebtokenを使用します。現在19,000以上のDependentsで使われているパッケージです。

$ npm i jsonwebtoken

# TypeScript環境の場合
$ npm i -D @types/jsonwebtoken

JWTをデコードする

まずデコード対象のCognitoのトークンを取得します。実際にはクライアント側での認証で取得されリクエストで送信されますが、ここでは下記方法で手動で取得してみます。

CognitoユーザーのIDトークンを取得できました。

$ npm run get-my-user-id-token

> aws-cdk-v2-project@0.1.0 get-my-user-id-token
> dotenv -e .env -- ./node_modules/.bin/ts-node ./get-cognito-my-user-id-token-helper.ts

ID_TOKEN="eyJraWQiOiJQZWlVNlpaQnJEWmJNTHRobmRNMjhza1Y3Q0tQTERpMlA4..."

jwt-decodeを使用してCognitoのJWTをデコードする処理です。デバッグのために取得したIDトークンを記載します。

decode-jwt.ts

import jwt_decode from 'jwt-decode';

export const get_jwt_decoded = (
  token: string
): {
  [name: string]: string;
} => {
  const decoded = jwt_decode<{ [name: string]: string }>(token);
  console.log(decoded); //デバッグ用
  return decoded;
};

//デバッグ用
get_jwt_decoded(
  'eyJraWQiOiJQZWlVNlpaQnJEWmJNTHRobmRNMjhza1Y3Q0tQTERpMlA4...'
);

上記スクリプトを実行すると、JWTがデコードされた内容が取得できました!

$  npx ts-node decode-jwt.ts
{
  sub: '88ffb38c-5c6b-4756-9770-76b45ff2fe71',
  email_verified: true,
  iss: 'https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxxxxxx',
  'cognito:username': '88ffb38c-5c6b-4756-9770-76b45ff2fe71',
  origin_jti: '6a039aec-1b38-4eef-b38a-9deff64853b3',
  aud: '3u95of1slb4921q28vqaeomibg',
  event_id: '0b468336-2d3c-48d7-ba17-209e88db3b06',
  token_use: 'id',
  auth_time: 1653142936,
  exp: 1653146536,
  iat: 1653142936,
  jti: 'e4c85ebc-a3d9-45f3-9510-73be008aec16',
  email: 'user@example.com'
}

JWTを作成してテストする

前節の処理をテストするために、JWTを作成するJestのテストを作成します。

テスト用のJWTの作成はjsonwebtokenを使用します。

test/decode-jwt.test.ts

import { sign } from 'jsonwebtoken';

import { get_jwt_decoded } from '../decode-jwt';

test('get_jwt_decoded', () => {
  const jwtPayload = {
    sub: '12345678-xxxx-1234-xxxx-123456789012',
    email: 'user@example.com',
  };
  const jwtSecret = 'jwt_secret';
  const token = sign(jwtPayload, jwtSecret);

  const res = get_jwt_decoded(token);

  expect(res).toStrictEqual({
    sub: '12345678-xxxx-1234-xxxx-123456789012',
    email: 'user@example.com',
    iat: expect.anything(),
  });
});

テストを実行してみると、作成したJWTでテストができています!

npx jest test/decode-jwt.test.ts
 PASS  test/decode-jwt.test.ts (5.011 s)
  ✓ get_jwt_decoded (15 ms)

  console.log
    {
      sub: '12345678-xxxx-1234-xxxx-123456789012',
      email: 'user@example.com',
      iat: 1653145828
    }

      at Object.<anonymous>.exports.get_jwt_decoded (decode-jwt.ts:9:11)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.055 s, estimated 6 s
Ran all test suites matching /test\/decode-jwt.test.ts/i.

おわりに

Node.jsとTypeScriptで、Amazon CognitoのJWTのデコード、およびJWTを作成してテストする方法を確認してみました。

Cognito認証により取得されたIDトークンから情報を取得して他の処理に使うことはよくあると思うので、そういう場合に役に立つと思います。

参考

以上