メインコンテンツへスキップ

AI を使用して Auth0 を統合する

Claude Code、Cursor、GitHub Copilot などの AI コーディングアシスタントを使用している場合は、agent skills を使って、数分で Auth0 API の認証を自動的に追加できます。インストール:
npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-express-api
次に、AI アシスタントに以下のように依頼します。
Add Auth0 JWT authentication to my Express API
AI アシスタントは、Auth0 API を自動的に作成し、認証情報を取得して、express-oauth2-jwt-bearer をインストールし、JWT ミドルウェアを設定したうえで、トークン検証によって API エンドポイントを保護します。agent skills の完全なドキュメント →
前提条件: 開始する前に、以下がインストールされていることを確認してください。
  • Node.js 18 LTS 以降 (^18.12.0 || ^20.2.0 || ^22.1.0 || ^24.0.0 をサポート)
  • npm 8 以降、yarn 1.22 以降、または pnpm 8 以降
インストールを確認するには、次を実行します: node --version && npm --versionExpress のバージョン互換性: このクイックスタートは Express 4.xExpress 5.x に対応しています。

はじめに

このクイックスタートでは、JWT アクセストークンを使用して Express.js API エンドポイントを保護する方法を説明します。Auth0 アクセストークンを検証し、ルートを保護して、スコープベースの認可を実装する安全な API を構築します。
1

新しいプロジェクトを作成

Express API 用の新しいディレクトリを作成し、Node.js プロジェクトを初期化します。
mkdir auth0-express-api && cd auth0-express-api
プロジェクトを初期化
npm init -y
プロジェクト構成を作成する
touch server.js .env
2

express-oauth2-jwt-bearer SDK をインストールします

必要な依存関係をインストールする
npm install express express-oauth2-jwt-bearer dotenv
package.json に起動用スクリプトを追加します:
package.json
{
  "scripts": {
    "start": "node server.js",
    "dev": "node --watch server.js"
  }
}
3

Auth0 API をセットアップする

次に、Auth0 テナントに新しい API を作成し、環境変数をプロジェクトに追加します。Auth0 API の設定方法は 2 つあります。CLI コマンドを使う方法と、Dashboard から手動で設定する方法です。
Auth0 API を作成するには、プロジェクトのルートディレクトリで次のコマンドを実行します。
# Auth0 CLI をインストールします(まだインストールしていない場合)
brew tap auth0/auth0-cli && brew install auth0

# Auth0 API を作成します
auth0 apis create \
  --name "My Express API" \
  --identifier https://my-express-api.example.com
このコマンドで次の処理が実行されます。
  1. 認証済みかどうかを確認します (必要に応じてログインを求めます)
  2. 指定した識別子で Auth0 API を作成します
  3. ドメインや識別子を含む API の詳細を表示します
作成後、IdentifierDomain の値をコピーし、.env ファイルを作成します。
.env
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
YOUR_AUTH0_DOMAIN は Auth0 テナントのドメイン (例: dev-abc123.us.auth0.com) に、YOUR_API_IDENTIFIER は API 識別子 (例: https://my-express-api.example.com) に置き換えてください。
.env ファイルが存在することを確認します: cat .env (Mac/Linux) または type .env (Windows)
4

JWT ミドルウェアを設定する

Express サーバーを作成し、JWT 検証を構成します。
server.js
require('dotenv').config();
const express = require('express');
const { auth } = require('express-oauth2-jwt-bearer');

const app = express();
const port = process.env.PORT || 3001;

// JWT検証ミドルウェアを設定する
const checkJwt = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
});

// サーバーを起動する
app.listen(port, () => {
  console.log(`API server running at http://localhost:${port}`);
});
この処理で行うこと:
  • Auth0 のドメインと API オーディエンスを使用して、JWT 検証ミドルウェアを作成します
  • 受信したアクセストークンの iss および aud クレームを検証します
  • 個々のルートを保護するために checkJwt を利用できるようにします
5

API ルートを作成

server.js にパブリックルートと保護されたルートを追加します。
server.js
require('dotenv').config();
const express = require('express');
const { auth, requiredScopes } = require('express-oauth2-jwt-bearer');

const app = express();
const port = process.env.PORT || 3001;

// JWT検証ミドルウェアの設定
const checkJwt = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
});

// パブリックルート - 認証不要
app.get('/api/public', (req, res) => {
  res.json({
    message: 'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
    timestamp: new Date().toISOString(),
  });
});

// 保護されたルート - 有効なアクセストークンが必要
app.get('/api/private', checkJwt, (req, res) => {
  res.json({
    message: 'Hello from a protected endpoint! You successfully authenticated.',
    user: req.auth.payload.sub,
    timestamp: new Date().toISOString(),
  });
});

// スコープ付き保護ルート - 'read:messages' スコープが必要
app.get('/api/private-scoped', checkJwt, requiredScopes('read:messages'), (req, res) => {
  res.json({
    message: 'Hello from a scoped endpoint! You have the required permission.',
    user: req.auth.payload.sub,
    scope: req.auth.payload.scope,
    timestamp: new Date().toISOString(),
  });
});

// エラー処理ミドルウェア
app.use((err, req, res, next) => {
  const status = err.status || 500;
  const message = err.message || 'Internal Server Error';

  res.status(status).json({
    error: err.code || 'server_error',
    message: status === 401 ? 'Authentication required' : message,
  });
});

// サーバーの起動
app.listen(port, () => {
  console.log(`API server running at http://localhost:${port}`);
});
要点:
  • パブリックルートでは認証は不要です
  • 保護されたルートでは、有効な JWT を要求するために checkJwt ミドルウェアを使用します
  • スコープ付きルートでは、トークン内の特定の権限を要求するために requiredScopes() を使用します
  • req.auth.payload には、認証済みリクエストのデコードされた JWT クレームが含まれます
  • sub クレームには、ユーザーの一意の識別子が含まれます
6

API を起動する

開発サーバーを起動します:
npm run dev
API は http://localhost:3001 で実行されています。
Node.js 18 以降では、--watch フラグを使用すると、ファイルの変更時にサーバーが自動的に再起動します。
7

APIをテストする

公開エンドポイントをテストします (認証は不要です) :
curl http://localhost:3001/api/public
以下のように表示されます:
{
  "message": "Hello from a public endpoint! You don't need to be authenticated to see this.",
  "timestamp": "2024-01-15T10:30:00.000Z"
}
トークンなしで保護されたエンドポイントをテストします (失敗するはずです) :
curl http://localhost:3001/api/private
401 Unauthorized エラーが表示されるはずです。
{
  "error": "unauthorized",
  "message": "Authentication required"
}
有効なトークンでテストするには、次の手順に従います。
  1. Auth0 DashboardApplicationsAPIs に移動します
  2. 対象の API を選択し、Test タブを開きます
  3. 生成されたアクセストークンをコピーします
保護されたエンドポイントをテストします。
curl http://localhost:3001/api/private \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
以下が表示されます:
{
  "message": "Hello from a protected endpoint! You successfully authenticated.",
  "user": "auth0|abc123...",
  "timestamp": "2024-01-15T10:30:00.000Z"
}
チェックポイントこれで、保護された API が用意できているはずです。API は次のとおりです。
  1. 認証なしでパブリックエンドポイントへのリクエストを受け付ける
  2. 有効なトークンなしで保護されたエンドポイントへのリクエストを拒否する
  3. JWT トークンを Auth0 のドメインと対象者に照らして検証する
  4. req.auth.payload を通じて、トークンのクレームに含まれるユーザー情報を提供する

高度な使い方

スコープを使用すると、きめ細かなアクセス制御を実現できます。エンドポイントごとに必要なスコープを指定できます。Auth0 でスコープを設定する:
  1. Auth0 DashboardApplicationsAPIs → 対象の API の順に移動します
  2. Permissions タブを開きます
  3. read:messageswrite:messagesadmin:access などの権限を追加します
スコープでルートを保護する:
server.js
const { auth, requiredScopes } = require('express-oauth2-jwt-bearer');

// 'read:messages' スコープが必要
app.get('/api/messages', checkJwt, requiredScopes('read:messages'), (req, res) => {
  res.json({
    messages: [
      { id: 1, text: 'Hello!' },
      { id: 2, text: 'World!' },
    ],
  });
});

// 'admin:access' スコープが必要
app.get('/api/admin', checkJwt, requiredScopes('admin:access'), (req, res) => {
  res.json({
    message: 'Admin access granted',
    userId: req.auth.payload.sub,
  });
});
リクエストに必要なスコープが含まれていない場合、API は insufficient_scope エラーとともに 403 Forbidden を返します。アクセストークンを取得する際に、クライアントアプリケーションが正しいスコープを要求するようにしてください。
スコープに加えて、JWT ペイロード内のカスタムクレームも検証できます。
server.js
const { auth, claimEquals, claimIncludes, claimCheck } = require('express-oauth2-jwt-bearer');

// クレーム値の完全一致を要求
app.get('/api/org/:orgId',
  checkJwt,
  claimEquals('org_id', 'org_123'),
  (req, res) => {
    res.json({ message: 'Organization access granted' });
  }
);

// クレームに指定したすべての値が含まれていることを要求
app.get('/api/roles',
  checkJwt,
  claimIncludes('roles', 'editor', 'viewer'),
  (req, res) => {
    res.json({ message: 'Role check passed' });
  }
);

// カスタムクレームの検証ロジック
app.get('/api/premium',
  checkJwt,
  claimCheck((claims) => {
    return claims.subscription === 'premium' && claims.verified === true;
  }),
  (req, res) => {
    res.json({ message: 'Premium feature access granted' });
  }
);
カスタムクレームは、標準の OIDC クレームでない限り、名前空間付き URL (例: https://myapp.com/roles) を使用する必要があります。カスタムクレームの詳細をご確認ください
同じルートで、認証済みアクセスと匿名アクセスの両方を許可できます。
server.js
const optionalAuth = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
  authRequired: false,
});

app.get('/api/feed', optionalAuth, (req, res) => {
  if (req.auth) {
    res.json({
      message: `Welcome back, ${req.auth.payload.sub}!`,
      personalizedContent: true,
    });
  } else {
    res.json({
      message: 'Welcome, guest!',
      personalizedContent: false,
    });
  }
});
Web アプリケーションからのリクエストを許可するには、CORS を有効にします。
npm install cors
server.js
const cors = require('cors');

app.use(cors({
  origin: ['http://localhost:3000', 'http://localhost:5173'],
  allowedHeaders: ['Authorization', 'Content-Type'],
  exposedHeaders: ['WWW-Authenticate'],
}));
本番環境では、正確なオリジンを指定してください。
server.js
app.use(cors({
  origin: [
    'https://myapp.com',
    'https://www.myapp.com'
  ],
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));
認証エラーに対する包括的なエラー処理を追加します。
server.js
const { UnauthorizedError, InvalidTokenError, InsufficientScopeError } = require('express-oauth2-jwt-bearer');

app.use((err, req, res, next) => {
  if (err instanceof InsufficientScopeError) {
    return res.status(403).json({
      error: 'forbidden',
      message: 'You do not have permission to access this resource',
      required_scopes: err.requiredScopes,
    });
  }

  if (err instanceof InvalidTokenError) {
    return res.status(401).json({
      error: 'invalid_token',
      message: 'The provided token is invalid or expired',
    });
  }

  if (err instanceof UnauthorizedError) {
    return res.status(401).set(err.headers).json({
      error: 'unauthorized',
      message: 'Authentication required',
    });
  }

  next(err);
});
TypeScript プロジェクトでは、型定義をインストールしてプロジェクトを設定します。
npm install -D typescript @types/express @types/node
server.ts を作成します。
server.ts
import 'dotenv/config';
import express, { Request, Response, NextFunction } from 'express';
import { auth, requiredScopes, UnauthorizedError } from 'express-oauth2-jwt-bearer';

const app = express();
const port = process.env.PORT || 3001;

const checkJwt = auth({
  issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
  audience: process.env.AUTH0_AUDIENCE,
});

app.get('/api/public', (req: Request, res: Response) => {
  res.json({ message: 'Public endpoint - no authentication required' });
});

app.get('/api/private', checkJwt, (req: Request, res: Response) => {
  res.json({
    message: 'Private endpoint',
    user: req.auth?.payload.sub,
  });
});

app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  if (err instanceof UnauthorizedError) {
    res.status(err.status).set(err.headers).json({
      error: err.code || 'unauthorized',
      message: 'Authentication required',
    });
  } else {
    res.status(500).json({
      error: 'server_error',
      message: 'Internal Server Error',
    });
  }
});

app.listen(port, () => {
  console.log(`API server running at http://localhost:${port}`);
});
tsconfig.json を追加します。
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "./dist"
  },
  "include": ["*.ts"]
}
次のコマンドで実行します: npx ts-node server.ts

トラブルシューティング

「認可トークンが見つかりませんでした」

問題: API がリクエスト内のアクセストークンを見つけられません。解決策:
  1. Authorization ヘッダーが含まれていることを確認します: Authorization: Bearer YOUR_TOKEN
  2. トークンの前に Bearer が含まれていることを確認します
  3. トークンの有効期限が切れていないことを確認します

「無効なトークン」または「jwt malformed」

問題: トークンの形式が無効です。解決策:
  1. アクセストークン を使用していることを確認します。IDトークンではありません
  2. トークンは API の audience パラメーターを指定して取得する必要があります
  3. トークンが有効な JWT であることを確認します (ドット区切りの 3 つの部分で構成されている必要があります)

想定外の「iss」または「aud」の値

問題: トークン内の Issuer または 対象者 が設定と一致していません。解決策:
  1. jwt.io でトークンをデコードします
  2. iss クレーム が https://YOUR_AUTH0_DOMAIN/ と一致することを確認します (末尾のスラッシュに注意)
  3. aud クレーム が AUTH0_AUDIENCE と完全に一致することを確認します
  4. .env の値を確認します:
AUTH0_DOMAIN=dev-abc123.us.auth0.com
AUTH0_AUDIENCE=https://my-express-api.example.com

「You must provide an issuerBaseURL」または「audience is required」

問題: 環境変数が読み込まれていません。解決策:
  1. .env ファイルがプロジェクトのルートに存在することを確認します
  2. dotenv がインストールされていることを確認します: npm install dotenv
  3. サーバーファイルの先頭に require('dotenv').config() を追加します
  4. 変数名が完全に一致していることを確認します (大文字と小文字は区別されます)

すべてのリクエストで 401 Unauthorized が返る

考えられる原因:
  • トークンの有効期限が切れている
  • 対象者 が一致していない
  • Issuer が一致していない
デバッグ手順:
  1. jwt.io でトークンをデコードします
  2. exp クレーム の期限が過ぎていないことを確認します
  3. aud クレーム が AUTH0_AUDIENCE と完全に一致することを確認します
  4. iss クレーム が https://{AUTH0_DOMAIN}/ であることを確認します
  5. Authorization ヘッダーの形式が Bearer YOUR_TOKEN であることを確認します (間にスペースが必要です)

「insufficient_scope」で 403 Forbidden が返る

問題: トークンに必要なスコープが含まれていません。解決策:
  1. 必要なスコープが Auth0 API で定義されていることを確認します (Dashboard → ApplicationsAPIsPermissions)
  2. トークン取得時に必要なスコープをリクエストします
  3. トークンの scope クレーム に必要なスコープが含まれていることを確認します

ブラウザーでの CORS エラー

問題: CORS ポリシーにより、ブラウザーが API リクエストをブロックしています。解決策: cors をインストールして設定します:
npm install cors
const cors = require('cors');

app.use(cors({
  origin: 'http://localhost:3000',
}));

次のステップ

保護されたAPIを用意できたら、次の内容も確認してください。

リソース