こうこく
作 ▸

TypeScriptでJSON Web Tokenの作成と検証を行う

JSON Web Tokenを使った認証みたいなものを実装したが、結局ボツになったので供養。

※記載の内容はDockerイメージ node:16-alpine から作成したコンテナ内で動作確認してます。他のOSだと鍵の作り方が違うかも。

Node.js v16.13.0jsonwebtoken 8.5.1

準備

必要なものをインストールする。

npm install typescript jsonwebtoken @types/node @types/jsonwebtoken
npm install --save-dev ts-node

これを書いた時の各パッケージのバージョンは以下。

package.json (抜粋)
{
  "dependencies": {
    "@types/jsonwebtoken": "^8.5.5",
    "@types/node": "^16.10.7",
    "jsonwebtoken": "^8.5.1",
    "typescript": "^4.4.4"
  },
  "devDependencies": {
    "ts-node": "^10.4.0"
  }
}

次に、以下コマンドで秘密鍵と公開鍵を作成。

openssl genrsa -out /path/to/private.key 2048
openssl rsa -in /path/to/private.key -pubout -out /path/to/public.key

実行

以下のソースコードを作成。JSON Web Tokenの作成と検証は、npmパッケージ jsonwebtoken で行います。

token.ts
import * as fs from 'fs';
import * as jwt from 'jsonwebtoken';

type TokenPayload = {
  dempa: string;
};

// 鍵をファイルから読み込み
const _privateKey = fs.readFileSync('/path/to/private.key');
const _publicKey = fs.readFileSync('/path/to/public.key');

// トークン生成
const payload = {
  dempa: 'yunyun',
};
const expirationSeconds = 60 * 5;  // 有効期限5分 (秒)
const token = jwt.sign(payload, _privateKey, { expiresIn: expirationSeconds, algorithm: 'RS256' });

console.log('token ->', token);

// トークン検証
let decoded: TokenPayload;
try {
  decoded = jwt.verify(token, _publicKey, { algorithms: ['RS256'] }) as TokenPayload;
} catch (e) {
  if (e instanceof jwt.TokenExpiredError) {
    console.error('トークンの有効期限が切れています。', e);
  } else if (e instanceof jwt.JsonWebTokenError) {
    console.error('トークンが不正です。', e);
  } else {
    console.error('トークンの検証でその他のエラーが発生しました。', e);
  }
  throw e;
}

console.log('decoded ->', decoded);

このコードを以下コマンドで実行。

npx ts-node token.ts

すると以下のように、JSON Web Tokenとペイロードが出力される。

token -> eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZW1wYSI6Inl1bnl1biIsImlhdCI6MTYzNjE4ODE0MywiZXhwIjoxNjM2MTg4NDQzfQ.lBUq1RUzy9ZJ-Nb59AWeMudQgyeHuXM0M1gwy_tTUNOzWEwHWMmpPEROyDtpA8yehlJHKzNlSEArgY2Bf-r0EBJz06BGVexfgMyTm1roITE7gZAj0M4Y0Roe2Q2bcYbKtUeRztm28uBorDnvx2iPUqBN7irCj2etx8Y0obwwwMs4W7YPnkcDcaw1M2RhffBGe8pWOB6FB5wZPcYoHRxVXn-8DYVYcwmmsAY-FsG2G7wduGfhYExGUgNodND1gTeG_feH_TSgc9XMP-v1T-sZjM3_fRql36Rpb6_w_jRa6kKTMJkWTz1-NxgenTPkom1wB9ibCtNkPs1jE9fSWv0l7g
decoded -> { dempa: 'yunyun', iat: 1636188143, exp: 1636188443 }

上記のJSON Web Tokenは、実際に自分がこの方法で作成したものなので、jwt.ioで中身を見れるはず。

以上。

この記事に何かあればこちらまで (非公開)