Node.js で JSON Web Token (JWT) の ID トークンを発行し、検証する処理のメモです。
JWT のメリットはアクセストークンそのものが有効期間やコンテクストを保持できるため、個別にリクエストごとにセッションIDからセッション情報を引くという機構を省くことができます。そのため、自前の API サーバにおいて、アクセストークンとして JWT の ID トークンを使えるとサーバ処理を省力化できます。
今回の例では、JWT の検証をグローバルにできるようにはせず、サーバ内でのみ行うこととします。一般的な JWT トークンは JSON Web Key (JWK) Set から提供されており、JWT の署名検証ができるようになっていますが、それは行いません。
依存ライブラリ Auth0 がものすごく便利なライブラリを提供してくれています。
https://github.com/auth0/node-jsonwebtoken
1 2 $ npm i -save jsonwebtoken $ npm i -save-dev @types/jsonwebtoken
鍵の生成 公開鍵と秘密鍵を別々にすることも可能ですが、分けると管理が面倒なのと同一サーバ内で処理するため、PEMファイルで管理します。
1 $ openssl genrsa > auth.pem
発行と検証処理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import fs from 'fs' import jwt from 'jsonwebtoken' const PEM = fs.readFileSync('auth.pem' )function issueToken (subject: string ): string { const opts: jwt.SignOptions = { algorithm: 'RS256' , issuer: 'https://issuer.example.com' , expiresIn: '1d' , } const payload = { sub: subject, } return jwt.sign(payload, PEM, opts) } export async function verifyToken (idToken: string ): Promise <object > { const opts: jwt.VerifyOptions = { algorithms: ['RS256' ], issuer: 'https://issuer.example.com' , maxAge: '1d' , } return new Promise ((resolve, reject ) => { jwt.verify(idToken, PEM, opts, (err: Error , decoded: any ) => { if (err) { reject(err) } else { resolve(decoded) } }) }) } ;(async () => { const idToken = issueToken('userId' ) const result = await verifyToken(idToken) console .log(result) })()
JWT 署名時の expiresIn より時間が経過している場合は、検証時に TokenExpiredError: jwt expired
がスローされます。
時間内であっても発行時よりも maxAge が経過している場合は、検証時に TokenExpiredError: maxAge exceeded
がスローされます。
実行結果 1 2 3 4 5 6 { sub: 'userId', iat: 1582639938, exp: 1582726338, iss: 'https://issuer.example.com' }
まとめ ログイン成功時に issueToken を呼んで ID トークンをクライアントに発行します。クライアントは API リクエストの Authorization ヘッダに付与して、サーバ側は verifyToken で検証することで、認証および subject(sub)フィールドなどからユーザー情報を取得することができます。
tilfin
freelance software engineer