auth0-php-api について
auth0-php-apiは、auth0/auth0-phpのAPIモードでAuth0アクセストークンを検証し、PHP APIエンドポイントを保護するためのスキルです。トークン検査、再利用可能なミドルウェア、スコープ、エンドポイントのテストを扱い、セッション型WebアプリではなくAPIを対象とします。
主な機能
- 01APIモードでのAuth0 SDK設定
- 02JWT署名とクレームの検証
- 03再利用可能なBearerトークンガードミドルウェア
- 04保護されたルートのスコープ確認
- 05公開・保護エンドポイントのテスト
活用シーン
- 01PHP APIルートへのAuth0トークン検証の追加
- 02許可されたスコープに基づくエンドポイント制限
- 03トークンを露出せずに公開・保護ルートをテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ auth0/ agent-skills --skill auth0-php-apiインストール後、Claude Code で/auth0-php-apiを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api.mdintegration.mdsetup.md詳細
Auth0 PHP API 連携
auth0/auth0-php の API モード(STRATEGY_API)で JWT アクセストークンを検証し、PHP API エンドポイントを保護します。
前提条件
- 拡張機能
mbstring、openssl、jsonを含む PHP 8.2 以降 - Composer がインストールされていること
- Auth0 API リソースが設定されていること(Application ではなく、API である必要があります)
- Auth0 の設定がまだ済んでいない場合は、まず
auth0-quickstartスキルを使用してください
使用しないケース
- ログイン/ログアウトフローを備えた PHP ウェブアプリケーション - セッションベースの認証には
auth0-phpを使用してください - Laravel アプリケーション - API ガードを標準でサポートする
auth0/laravel-auth0を使用してください - Symfony アプリケーション - セキュリティバンドルを備えた
auth0/symfonyを使用してください - シングルページアプリケーション - クライアント側の認証には
auth0-react、auth0-vue、またはauth0-angularを使用してください - トークンの発行 - このスキルはアクセストークンの検証用であり、発行用ではありません
クイックスタートのワークフロー
1. SDK をインストールする
composer require auth0/auth0-php vlucas/phpdotenv guzzlehttp/guzzle guzzlehttp/psr7 "symfony/cache:^7.0"
auth0/auth0-php- Auth0 SDK(v8.x)vlucas/phpdotenv-.envファイルを$_ENVに読み込みますguzzlehttp/guzzle+guzzlehttp/psr7- SDK が必要とする PSR-18 HTTP クライアントsymfony/cache- JWKS キーのキャッシュに使用する PSR-6 キャッシュ(本番環境で推奨)
2. Auth0 API を作成する
Auth0 に API を作成する必要があります(Application ではありません)。
停止して、先にユーザーに確認してください。
ほかの作業を行う前に、次の質問をそのまま尋ね、回答を待ってください。
"Auth0 API リソースをどのように作成しますか?
- 自動 - Auth0 CLI スクリプトを実行してリソースを作成し、正確な値を
.envに自動で書き込みます。- 手動 - Auth0 Dashboard(または
auth0 apis create)でご自身で API を作成し、Domain と Audience を教えてください。どちらにしますか?(1 = 自動/2 = 手動)"
ユーザーが回答するまで、セットアップ手順に進まないでください。手動をデフォルトにしないでください。
ユーザーが「自動」を選んだ場合は、CLI スクリプトの全手順が記載されたセットアップガイドに従ってください。自動の手順では .env が作成されるため、以下のステップ 3 を省略し、ステップ 4 に進んでください。
ユーザーが「手動」を選んだ場合は、詳細な手順が記載されたセットアップガイドの「手動セットアップ」セクションに従ってください。その後、以下のステップ 3 に進んでください。
手動で API を作成する場合のクイックリファレンス:
# Using Auth0 CLI
auth0 apis create \
--name "My PHP API" \
--identifier https://my-api.example.com \
--json
または、Auth0 Dashboard -> Applications -> APIs で手動作成します。
3. 環境を設定する
.env を作成します。
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_AUDIENCE=https://your-api.example.com
AUTH0_DOMAIN は Auth0 テナントのドメインです(https:// は含めません)。AUTH0_AUDIENCE は、Auth0 で API リソースを作成したときに設定した API 識別子です。
4. API モードで Auth0 を初期化する
SDK を初期化するために auth0.php を作成します。
<?php
require 'vendor/autoload.php';
use Auth0\SDK\Auth0;
use Auth0\SDK\Configuration\SdkConfiguration;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$configuration = new SdkConfiguration(
strategy: SdkConfiguration::STRATEGY_API,
domain: $_ENV['AUTH0_DOMAIN'],
clientId: null,
audience: [$_ENV['AUTH0_AUDIENCE']],
tokenAlgorithm: 'RS256',
tokenCache: new FilesystemAdapter('auth0_jwks', 600, __DIR__ . '/var/cache'),
tokenCacheTtl: 600,
);
$auth0 = new Auth0($configuration);
ウェブアプリモードとの主な違い:
STRATEGY_API- ステートレスで、セッションや Cookie を使用しません- RS256 の検証では
clientIdは不要です(HS256 の場合のみ必要です) audienceには、許可する Audience 文字列の配列を指定できますtokenCacheは、JWKS キャッシュ用の PSR-6CacheItemPoolInterfaceです
5. ミドルウェア関数を作成する
SDK には組み込みのミドルウェアがないため、再利用可能なガード関数を作成します。middleware.php を作成します。
<?php
use Auth0\SDK\Auth0;
use Auth0\SDK\Token;
use Auth0\SDK\Exception\InvalidTokenException;
function requireAuth(Auth0 $auth0, ?array $requiredScopes = null): array
{
$token = $auth0->getBearerToken(
server: ['HTTP_AUTHORIZATION']
);
if ($token === null) {
http_response_code(401);
header('Content-Type: application/json');
echo json_encode(['error' => 'unauthorized', 'message' => 'Missing or invalid Bearer token']);
exit;
}
$claims = $token->toArray();
if ($requiredScopes !== null) {
$grantedScopes = isset($claims['scope']) ? explode(' ', $claims['scope']) : [];
$missingScopes = array_diff($requiredScopes, $grantedScopes);
if (!empty($missingScopes)) {
http_response_code(403);
header('Content-Type: application/json');
echo json_encode(['error' => 'insufficient_scope', 'message' => 'Token lacks required scopes']);
exit;
}
}
return $claims;
}
getBearerToken() は、指定した場所から Bearer トークンを検索し、JWKS エンドポイントに対して署名を検証して、クレーム(issuer、audience、有効期限)を検証します。server パラメーターは、確認対象となる $_SERVER のキー名の配列(例:['HTTP_AUTHORIZATION'])であり、$_SERVER 自体ではありません。有効なトークンが見つかった場合は TokenInterface を返し、見つからない場合は null を返します(例外はスローしません)。
6. API ルートを作成する
フロントコントローラーとして index.php を作成します。
<?php
require 'auth0.php';
require 'middleware.php';
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
header('Content-Type: application/json');
switch ($path) {
case '/api/public':
echo json_encode(['message' => 'Public endpoint - no authentication required']);
break;
case '/api/private':
$claims = requireAuth($auth0);
echo json_encode(['message' => 'Private endpoint', 'sub' => $claims['sub']]);
break;
case '/api/private-scoped':
$claims = requireAuth($auth0, ['read:messages']);
echo json_encode(['messages' => [], 'sub' => $claims['sub']]);
break;
default:
http_response_code(404);
echo json_encode(['error' => 'not_found']);
break;
}
7. アクセストークンのクレーム
デコードされた JWT クレームは連想配列として返されます。
$claims = requireAuth($auth0);
$userId = $claims['sub']; // user/client ID
$scopes = $claims['scope']; // space-separated granted scopes
$issuer = $claims['iss']; // issuer (your Auth0 domain URL)
$audience = $claims['aud']; // audience (string or array)
$expiration = $claims['exp']; // expiration timestamp
Token オブジェクトの型付きアクセサーメソッドも使用できます。
$token = $auth0->getBearerToken(server: ['HTTP_AUTHORIZATION']);
if ($token !== null) {
$subject = $token->getSubject(); // returns ?string
$issuer = $token->getIssuer(); // returns ?string
$audience = $token->getAudience(); // returns ?array
$expiration = $token->getExpiration(); // returns ?int
}
8. CORS ヘッダーを追加する
ブラウザー上で動作する SPA から API にリクエストが届く場合は、CORS ヘッダーを追加します。cors.php を作成します。
<?php
function handleCors(array $allowedOrigins): void
{
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins, true)) {
header("Access-Control-Allow-Origin: $origin");
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type');
header('Access-Control-Max-Age: 86400');
}
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
}
次に、既存の require 'auth0.php' 行より前に、index.php の先頭に以下の行を追加します。
require 'cors.php';
handleCors(['https://your-spa-domain.com']);
更新後の index.php の先頭部分は次のようになります。
<?php
require 'cors.php';
handleCors(['https://your-spa-domain.com']);
require 'auth0.php';
require 'middleware.php';
// ... rest of index.php
プリフライトの OPTIONS リクエストがトークンの検証を行わずに処理を終了するよう、CORS は認証より先に処理する必要があります。
9. API をテストする
エージェントへの指示: PHP の組み込みサーバーを起動し、認証情報なしで基本的なエンドポイントが動作することを確認します。
php -S localhost:8000 index.php & sleep 1 curl -s http://localhost:8000/api/public curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/api/private
/api/publicは{"message":"Public endpoint - no authentication required"}を返すはずです。/api/privateは HTTP 401 を返すはずです。どちらも成功した場合、ミドルウェアは動作しています。完了したら、バックグラウンドで起動したサーバーを終了します。
kill %1 2>/dev/null失敗時の確認: サーバーの起動に失敗する場合や
/api/publicでエラーが発生する場合は、PHP の構文エラーまたは.envの不足を確認してください。5〜6 回試しても失敗する場合は、AskUserQuestionを使って、ユーザーの環境について詳しく尋ねてください。
エージェントへの指示:基本テストが成功したら停止して、ユーザーに確認してください。
public/401 のテストが成功したら、ユーザーに尋ねます。
「API のセットアップが完了し、ミドルウェアも動作しています(トークンなしの場合、public は 200 を返し、private は 401 を返します)。実際のアクセストークンを使ったテストのセットアップもお手伝いしましょうか?
- はい — テスト用トークンを取得するために、M2M アプリケーションの設定をお手伝いします。
- いいえ — 今回はこれで終了します。
どちらにしますか?」
ユーザーが「はい」と言わない限り、M2M/トークンのセットアップに進まないでください。「いいえ」と言われた場合は、完了した内容をまとめて終了してください。
エージェントへの指示(M2M アプリのセットアップ — テストを希望する場合のみ):
ユーザーがテストのセットアップを選択した場合は、次のように尋ねます。
「保護されたエンドポイントをテストするには、この API のトークンをリクエストする権限を持つ Machine-to-Machine(M2M)アプリケーションが必要です。
- 新規作成 — 新しい M2M アプリケーションを作成し、この API の利用を許可します。
- 既存のアプリケーションを使用 — すでに M2M アプリケーションがある場合は、Client ID を教えてください。この API の利用を許可します。
どちらにしますか?(1 = 新規作成/2 = 既存のアプリケーションを使用)」
ユーザーが回答するまで先に進まないでください。テナント内にある既存のアプリケーションを、確認せずに選択しないでください。
ユーザーが「新規作成」を選択した場合:
auth0 apps create \ --name "${PWD##*/} (Test App)" \ --type m2m \ --no-input --jsonJSON を
jqで解析してclient_idを抽出します。--reveal-secretsは使用しないでください。エージェントのコンテキストにクライアントシークレットを決して公開しないでください。 次に、クライアントグラントを作成します。auth0 api post "client-grants" --data '{ "client_id": "<CLIENT_ID>", "audience": "<API_IDENTIFIER>", "scope": ["<SCOPES>"] }'ユーザーが「既存のアプリケーションを使用」を選択した場合: Client ID を尋ねます。次に、この API の利用を許可するクライアントグラントを作成します。
auth0 api post "client-grants" --data '{ "client_id": "<USER_PROVIDED_CLIENT_ID>", "audience": "<API_IDENTIFIER>", "scope": ["<SCOPES>"] }'グラントがすでに存在する場合(409 conflict)は問題ありません。アプリケーションはすでに許可されています。 エージェントへの指示(トークンの隔離 — 重要):
エージェントは、アクセストークンの値を直接見たり、表示したりしてはなりません。トークンのセキュリティに関するルール:
auth0 test tokenを単独で実行しないでください。トークンが標準出力に出力されます- ユーザーに会話内でトークンを貼り付けるよう求めないでください
- トークンの値をエコー、出力、ログに記録しないでください
- トークンをファイルに保存しないでください
安全なテスト方法(単一コマンドチェーン):
ユーザーが保護されたエンドポイントのテストを明示的に依頼した場合は、トークンをシェル変数に取り込み、直ちに使用する単一コマンドチェーンを使ってください。
php -S localhost:8000 index.php & sleep 1 TEST_TOKEN=$(auth0 test token <M2M_CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> 2>/dev/null | grep -o 'ey[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*') && \ [ -n "$TEST_TOKEN" ] && echo "Token acquired (${#TEST_TOKEN} chars)" && \ echo "=== GET /api/private ===" && \ curl -s http://localhost:8000/api/private -H "Authorization: Bearer $TEST_TOKEN" && \ echo "" && echo "=== GET /api/private-scoped ===" && \ curl -s http://localhost:8000/api/private-scoped -H "Authorization: Bearer $TEST_TOKEN" kill %1 2>/dev/nullルール:
- ユーザーから明示的にテストを依頼された場合にのみ使用してください
- トークンの取得と
curlは、必ず単一の&&コマンドに連結してくださいecho $TEST_TOKENや、トークンの値をそのまま出力するコマンドは絶対に追加しないでください- トークンの取得に失敗した場合(変数が空の場合)は、M2M アプリが認可されていない可能性があることを伝えてください
- クライアント ID は必須です。M2M の設定が完了していない場合は、まずユーザーに確認してください
ユーザーがテストを依頼していない場合は、手動で実行するコマンドを提示してください。
auth0 test token <CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> curl http://localhost:8000/api/private -H "Authorization: Bearer <PASTE_TOKEN_HERE>"
サーバーを起動します:
php -S localhost:8000 index.php
公開エンドポイントをテストします(トークンは不要です):
curl http://localhost:8000/api/public
トークンなしで保護されたエンドポイントをテストします(401 が返るはずです):
curl http://localhost:8000/api/private
トークンを使って保護されたエンドポイントをテストします:
curl http://localhost:8000/api/private \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
スコープ付きエンドポイントをテストします:
curl http://localhost:8000/api/private-scoped \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Auth0 Dashboard -> APIs -> Test タブ、または上記の M2M フローでテストトークンを取得します。
よくある間違い
| 間違い | 修正方法 |
|---|---|
ソースコードで domain や audience をハードコードする | 常に環境変数から読み込みます。コードに認証情報を埋め込まないでください |
API に STRATEGY_REGULAR を使用する | API モードでは SdkConfiguration::STRATEGY_API を使用する必要があります。セッションと Cookie が無効になります |
| PSR-18 HTTP クライアントをインストールせずに使用する | guzzlehttp/guzzle または別の PSR-18 クライアントが必要です。ない場合、SDK は JWKS を取得できません |
| JWKS キーをキャッシュしない | PSR-6 キャッシュがない場合、SDK はリクエストごとに JWKS を取得します。必ず tokenCache を設定してください |
audience に文字列を渡す | audience は配列である必要があります。'https://my-api.example.com' ではなく、['https://my-api.example.com'] を指定してください |
domain に https:// を含む完全な URL を渡す | domain には https://my-tenant.us.auth0.com ではなく、my-tenant.us.auth0.com のようなドメインのみを指定してください |
トークンの種類を指定せずに decode() を使用する | decode() を手動で呼び出す場合は、必ず tokenType: Token::TYPE_ACCESS_TOKEN を渡してください |
| 例外メッセージをユーザーに表示する | 実際のエラーには error_log() を使用し、一般的な JSON エラーメッセージを返してください |
| アクセストークンではなく ID トークンを使用する | API 認証には アクセストークン を使用する必要があります。ID トークンはクライアントアプリ用です |
| Auth0 で API ではなく Application を作成する | API リソースを作成する必要があります(Applications -> APIs)。Application は正しい audience を持つアクセストークンを発行しません |
clientId を設定し、RS256 で必要だと想定する | RS256 では clientId は任意です。SDK は JWKS エンドポイントに対して検証します |
RS256 の検証に clientSecret を使用する | clientSecret が必要なのは HS256 のみです。RS256 では JWKS の公開鍵を使用します |
$_SERVER をそのまま getBearerToken() に渡す | server パラメーターには、検索するキー名の配列(例:['HTTP_AUTHORIZATION'])を指定します。$_SERVER 自体ではありません |
主要な SDK メソッド
| メソッド | 戻り値 | 用途 |
|---|---|---|
getBearerToken | ?TokenInterface | 指定された $_SERVER のキーから Bearer トークンを検索し、署名を検証してクレームを検証します。トークンが見つからない場合、または検証に失敗した場合は null を返します(例外はスローしません)。 |
decode | TokenInterface | JWT 文字列を手動でデコードして検証します |
configuration | SdkConfiguration | SDK 設定インスタンスにアクセスします |
Token::toArray | array | すべてのトークンクレームを連想配列として返します |
Token::getSubject | ?string | sub クレーム(ユーザー/クライアント ID)を返します |
Token::getIssuer | ?string | iss クレームを返します |
Token::getAudience | ?array | aud クレームを返します |
Token::getExpiration | ?int | exp クレーム(Unix タイムスタンプ)を返します |
関連スキル
auth0-php- セッションベースの認証でログイン/ログアウトする PHP ウェブアプリ向けauth0-quickstart- Auth0 の基本設定とフレームワークの検出auth0-cli- ターミナルから Auth0 リソースを管理auth0-mfa- 多要素認証を追加
クイックリファレンス
API 用の SdkConfiguration:
$configuration = new SdkConfiguration(
strategy: SdkConfiguration::STRATEGY_API, // required - stateless mode
domain: $_ENV['AUTH0_DOMAIN'], // required
audience: [$_ENV['AUTH0_AUDIENCE']], // required - array of identifiers
tokenAlgorithm: 'RS256', // default
tokenCache: $psrCacheAdapter, // recommended for production
tokenCacheTtl: 600, // JWKS cache TTL in seconds
);
トークンの検証:
$token = $auth0->getBearerToken(server: ['HTTP_AUTHORIZATION']); // returns ?TokenInterface
$claims = $token->toArray(); // all claims as array
$userId = $token->getSubject(); // sub claim
手動デコード:
use Auth0\SDK\Token;
$token = $auth0->decode(
$jwtString,
tokenType: Token::TYPE_ACCESS_TOKEN,
);
環境変数:
AUTH0_DOMAIN- Auth0 テナントのドメイン(例:tenant.us.auth0.com)AUTH0_AUDIENCE- API 識別子(例:https://api.example.com)
一般的なユースケース:
- ルートの保護 ->
requireAuth($auth0)(ステップ 5 を参照) - スコープの適用 ->
requireAuth($auth0, ['read:messages'])(ステップ 5 を参照) - CORS の設定 -> 統合ガイド
- 複数 audience の検証 -> 統合ガイド
- 高度な設定 -> API リファレンス
詳細ドキュメント
- セットアップガイド - Auth0 CLI のセットアップ、環境設定、テストトークンの取得
- 統合ガイド - スコープ、権限、ミドルウェア、複数のオーディエンス、CORS、エラー処理
- API リファレンス - API モード向けの SDK API 全般、設定オプション、トークンメソッド