JWT

ジェイダブリューティー

JWT(JSON Web Token)を分かりやすく

JWTは、情報を安全に交換するためのコンパクトで自己完結型の方法を提供することを目的としています。要するに、JWTは、ある情報を秘密鍵(あるいは公開鍵)でデジタル署名することにより、その情報の完全性を保証します。

具体的な例で説明すると、JWTはまるでパスポートのようなものです。パスポートにはあなたの写真、名前、国籍などの情報が記載されていますよね。それはあなたが誰であるかを証明するもので、それがないと国境を越えることはできません。

JWTも同様に、ユーザーが誰であるか(認証情報)や何ができるか(認可情報)といった情報を持っています。そしてその情報は、秘密鍵で署名されているため、改ざんされていないことが保証されています。

さて、ユーザーがログインすると、サーバーはユーザー情報を含むJWTを作成し、それをユーザーに返します。ユーザーはそのJWTを保持し、次にサーバーにリクエストを送る際にはそのJWTを一緒に送ります。サーバーはそのJWTを検証し、問題がなければリクエストを処理します。

なんだか大変そうですよね?でもこれがJWTの基本的な仕組みです。セキュリティを確保しつつ、ユーザー情報を効率的に取り扱うための仕組みなんですよ。一体ナンノコッチャ?って思うかもしれませんが、基本的には「あなたがあなたであることを証明するためのパスポート」だと思ってもらえれば大丈夫ですよ!ここまで大丈夫ですか?

JWT(JSON Web Token、ジェイダブリューティー)とは、セキュアな情報のやりとりや認証を行うための軽量なトークンフォーマットです。JWT は主に以下の 3 つの部分から構成されています。

  1. Header: トークンのタイプや使用しているアルゴリズムを表す。
  2. Payload: トークンに含まれるデータ(クレーム)を表す。
  3. Signature: トークンの整合性を検証するための署名。

これらの部分は、それぞれ Base64Url エンコードされており、.(ドット)で連結されています。Next.js と TypeScript のプロジェクトで JWT を利用する場合、認証や認可の処理を実装する際に使用されます。

JWT を利用した認証

Next.js と TypeScript で JWT を利用した認証を実装してみましょう。以下の例では、ログイン処理で JWT を発行し、API ルートで JWT を検証しています。

1 JWT ライブラリのインストール

まず、jsonwebtoken ライブラリをインストールします。

npm install jsonwebtoken

2 ログイン処理

ログイン処理を実装するために、/pages/api/login.ts ファイルを作成します。

// pages/api/login.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import jwt from 'jsonwebtoken'

const SECRET = 'your-secret-key'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    const { username, password } = req.body

    // 本来はデータベースなどでユーザーの認証を行いますが、
    // ここでは簡単化のために固定のユーザー名とパスワードを使用しています。
    if (username === 'user' && password === 'password') {
      const token = jwt.sign({ username }, SECRET, { expiresIn: '1h' })
      res.status(200).json({ token })
    } else {
      res.status(401).json({ error: 'Invalid credentials' })
    }
  } else {
    res.setHeader('Allow', 'POST')
    res.status(405).end('Method Not Allowed')
  }
}

3 API ルートで JWT の検証

JWT を検証するために、API ルート(例:/pages/api/protected.ts)を作成します。

// pages/api/protected.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import jwt from 'jsonwebtoken'

const SECRET = 'your-secret-key'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'GET') {
    const token = req.headers.authorization?.split(' ')[1]

    if (!token) {
      res.status(401).json({ error: 'No token provided' })
      return
    }

    try {
      const decoded = jwt.verify(token, SECRET)
      res.status(200).json({ data: 'Protected data', user: decoded })
    } catch (error) {
      res.status(401).json({ error: 'Invalid token' })
    }
  } else {
    res.setHeader('Allow', 'GET')
    res.status(405).end('Method Not Allowed')
  }
}

このコードでは、API ルートにアクセスする際に、Authorization ヘッダーに JWT が含まれているかを確認し、正しい JWT であれば保護されたデータを返しています。JWT が無効または提供されていない場合、エラーが返されます。

JWT の注意点

JWT を利用する際には、いくつかの注意点があります。

  1. セキュリティ: JWT のペイロードは Base64Url エンコードされていますが、暗号化されていません。機密情報はペイロードに含めないでください。
  2. 有効期限: JWT には有効期限が設定されることが一般的です。これにより、トークンが無期限に利用されることを防ぐことができます。
  3. 保存場所: JWT はクライアントサイドで安全に保存する必要があります。一般的には、HTTP Only Cookie を使用して JWT を保存することが推奨されています。

まとめ

JWT(JSON Web Token)は、セキュアな情報のやりとりや認証を行うための軽量なトークンフォーマットです。この記事では、Next.js と TypeScript のプロジェクトで JWT を利用する方法として、ログイン処理で JWT を発行し、API ルートで JWT を検証する例を紹介しました。ただし、JWT を利用する際には、セキュリティや有効期限、保存場所に注意することが重要です。