auth0-php について
auth0/auth0-php を使い、PHP Web アプリに Auth0 のログイン、ログアウト、プロフィール表示を追加するためのスキルです。設定、ルート、暗号化 Cookie セッション、実装時の一般的な問題を扱います。
主な機能
- 01Auth0 SDK の導入と設定
- 02ログインおよびコールバックルートの実装
- 03セッション確認によるプロフィールルートの保護
- 04暗号化 Cookie セッションの管理
- 05ログアウトとトークン更新への対応
活用シーン
- 01PHP Web アプリへの Auth0 ログイン追加
- 02認可コード交換用のコールバックルート構築
- 03ログインユーザーに限定したプロフィールページ
- 04PHP の Auth0 設定の問題解決
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ auth0/ agent-skills --skill auth0-phpインストール後、Claude Code で/auth0-phpを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api.mdintegration.mdsetup.md詳細
Auth0 PHP Web App Integration
auth0/auth0-phpを使用して、PHP Webアプリケーションにログイン、ログアウト、ユーザープロフィール機能を追加します。
前提条件
- 拡張機能
mbstring、openssl、jsonを含むPHP 8.2以降 - Composerがインストールされていること
- Auth0 Regular Web Applicationが設定されていること(APIではなく、Applicationである必要があります)
- Auth0のセットアップがまだの場合は、まず
auth0-quickstartスキルを使用してください
使用しないケース
- JWT Bearer検証を行うPHP API - ステートレスなAPIトークン検証には
auth0-php-apiを使用してください - Laravelアプリケーション - 専用のLaravel統合
auth0/laravel-auth0を使用してください - Symfonyアプリケーション - 専用のSymfony統合
auth0/symfonyを使用してください - シングルページアプリケーション - クライアント側の認証には
auth0-react、auth0-vue、またはauth0-angularを使用してください - Next.jsアプリケーション - クライアントとサーバーの両方に対応する
auth0-nextjsを使用してください - Node.js Webアプリ - セッションベースの認証には
auth0-expressまたはauth0-fastifyを使用してください
クイックスタートのワークフロー
1. SDKをインストールする
composer require auth0/auth0-php vlucas/phpdotenv guzzlehttp/guzzle guzzlehttp/psr7
auth0/auth0-php- Auth0 SDKvlucas/phpdotenv-.envファイルを$_ENVに読み込みますguzzlehttp/guzzle+guzzlehttp/psr7- SDKで必要となるPSR-18 HTTPクライアント
2. 環境を設定する
.envを作成します。
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_CLIENT_ID=your_client_id
AUTH0_CLIENT_SECRET=your_client_secret
AUTH0_COOKIE_SECRET=your_generated_secret
AUTH0_REDIRECT_URI=http://localhost:3000/callback
AUTH0_DOMAINはAuth0テナントのドメインです(https://は含めません)。AUTH0_CLIENT_IDとAUTH0_CLIENT_SECRETはAuth0 Applicationの設定から取得します。AUTH0_COOKIE_SECRETはセッションクッキーの暗号化に使用します。openssl rand -hex 32で生成してください。
3. Auth0 Dashboardを設定する
Auth0 Applicationの設定で、次のようにします。
- Application Type:Regular Web Application
- Allowed Callback URLs:
http://localhost:3000/callback - Allowed Logout URLs:
http://localhost:3000
4. Authの設定を作成する
SDKを初期化するためにauth0.phpを作成します。
<?php
require 'vendor/autoload.php';
use Auth0\SDK\Auth0;
use Auth0\SDK\Configuration\SdkConfiguration;
// Load environment variables
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$configuration = new SdkConfiguration(
strategy: SdkConfiguration::STRATEGY_REGULAR,
domain: $_ENV['AUTH0_DOMAIN'],
clientId: $_ENV['AUTH0_CLIENT_ID'],
clientSecret: $_ENV['AUTH0_CLIENT_SECRET'],
cookieSecret: $_ENV['AUTH0_COOKIE_SECRET'],
redirectUri: $_ENV['AUTH0_REDIRECT_URI'],
scope: ['openid', 'profile', 'email'],
);
$auth0 = new Auth0($configuration);
Auth0インスタンスを1つ作成し、再利用してください。認証情報をハードコードせず、必ず環境変数を使用してください。
仕組み: SDKは、cookieSecretからHKDF-SHA256を介して導出したキーを使い、AES-256-GCMでセッションデータ(トークン、ユーザープロフィール)を暗号化します。デフォルトでは、セッションデータは暗号化されたクッキーに保存されるため、サーバー側のデータベースは不要です。
5. インデックスページ(ルーター)を作成する
シンプルなフロントコントローラーとしてindex.phpを作成します。まずroutes/ディレクトリを作成してください。
<?php
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if ($path === '/style.css') {
header('Content-Type: text/css');
readfile(__DIR__ . '/style.css');
exit;
}
require 'auth0.php';
switch ($path) {
case '/':
require 'routes/home.php';
break;
case '/login':
require 'routes/login.php';
break;
case '/callback':
require 'routes/callback.php';
break;
case '/profile':
require 'routes/profile.php';
break;
case '/logout':
require 'routes/logout.php';
break;
default:
http_response_code(404);
echo 'Not found';
break;
}
/style.cssの静的ファイルハンドラーはrequire 'auth0.php'より前に配置されているため、SDKを初期化せずにスタイルシートを読み込めます。
6. スタイルシートを追加する
style.cssを作成します。
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f7fa;
color: #1a1a2e;
line-height: 1.6;
min-height: 100vh;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 40px 20px;
}
.card {
background: #fff;
border-radius: 12px;
padding: 28px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
border: 1px solid #e8ecf0;
}
.card.center {
text-align: center;
padding: 60px 28px;
}
h1 {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 4px;
}
h2 {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 16px;
color: #444;
}
.subtitle {
color: #666;
font-size: 0.95rem;
}
.card.center .subtitle {
margin: 12px 0 28px;
}
.user-header {
display: flex;
align-items: center;
gap: 16px;
}
.avatar {
width: 48px;
height: 48px;
border-radius: 50%;
object-fit: cover;
}
.avatar-lg {
width: 72px;
height: 72px;
}
.nav-links {
margin-top: 20px;
display: flex;
gap: 12px;
}
.top-nav {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.btn {
display: inline-block;
padding: 10px 20px;
border-radius: 8px;
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
transition: all 0.15s ease;
}
.btn-primary {
background: #635bff;
color: #fff;
}
.btn-primary:hover {
background: #4b44d4;
}
.btn-secondary {
background: #f0f0f5;
color: #444;
}
.btn-secondary:hover {
background: #e4e4ec;
}
.btn-back {
background: none;
color: #635bff;
padding: 10px 0;
}
.btn-back:hover {
color: #4b44d4;
}
.info-table {
width: 100%;
border-collapse: collapse;
}
.info-table tr {
border-bottom: 1px solid #f0f0f5;
}
.info-table tr:last-child {
border-bottom: none;
}
.info-table td {
padding: 10px 0;
vertical-align: top;
}
.info-table .label {
font-weight: 500;
color: #666;
width: 160px;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.02em;
}
.info-table .value {
color: #1a1a2e;
word-break: break-all;
}
.token-box {
background: #f8f9fb;
border: 1px solid #e8ecf0;
border-radius: 8px;
padding: 14px;
font-size: 0.8rem;
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
word-break: break-all;
white-space: pre-wrap;
max-height: 120px;
overflow-y: auto;
margin-bottom: 16px;
}
7. ホームルートを追加する
routes/home.phpを作成します。
<?php
$credentials = $auth0->getCredentials();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Auth0 PHP App</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div class="container">
<?php if ($credentials): ?>
<div class="card">
<div class="user-header">
<img src="<?= htmlspecialchars($credentials->user['picture'] ?? '') ?>" alt="avatar" class="avatar" />
<div>
<h1>Hello, <?= htmlspecialchars($credentials->user['name'] ?? 'User') ?>!</h1>
<p class="subtitle"><?= htmlspecialchars($credentials->user['email'] ?? '') ?></p>
</div>
</div>
<nav class="nav-links">
<a href="/profile" class="btn btn-primary">View Profile & Tokens</a>
<a href="/logout" class="btn btn-secondary">Logout</a>
</nav>
</div>
<?php else: ?>
<div class="card center">
<h1>Auth0 PHP Web App</h1>
<p class="subtitle">Session-based authentication with Auth0 SDK</p>
<a href="/login" class="btn btn-primary">Login</a>
</div>
<?php endif; ?>
</div>
</body>
</html>
8. ログインルートを追加する
routes/login.phpを作成します。
<?php
header('Location: ' . $auth0->login());
exit;
login()はAuth0のUniversal Loginページを指すURL文字列を返します。ユーザーをそのURLにリダイレクトする必要があります。
9. コールバックルートを追加する
routes/callback.phpを作成します。
<?php
if (null !== $auth0->getExchangeParameters()) {
try {
$auth0->exchange();
header('Location: /');
exit;
} catch (\Exception $e) {
error_log('Auth0 callback error: ' . $e->getMessage());
http_response_code(400);
echo "Authentication failed. Please try again.";
exit;
}
}
header('Location: /');
exit;
getExchangeParameters()は、コールバックに認可コードのパラメーターが含まれているかを確認します。exchange()はコードをトークンと交換し、セッションを確立します。トークン交換は失敗する可能性があるため(コードの期限切れ、CSRFの不一致など)、必ずtry/catchで囲んでください。
10. プロフィールルートを追加する(保護対象)
routes/profile.phpを作成します。
<?php
$credentials = $auth0->getCredentials();
if (null === $credentials) {
header('Location: /login');
exit;
}
$user = $credentials->user;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Profile - Auth0 PHP App</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div class="container">
<nav class="top-nav">
<a href="/" class="btn btn-back">← Back to Home</a>
<a href="/logout" class="btn btn-secondary">Logout</a>
</nav>
<div class="card">
<div class="user-header">
<img src="<?= htmlspecialchars($user['picture'] ?? '') ?>" alt="avatar" class="avatar avatar-lg" />
<div>
<h1><?= htmlspecialchars($user['name'] ?? 'User') ?></h1>
<p class="subtitle"><?= htmlspecialchars($user['email'] ?? '') ?></p>
</div>
</div>
</div>
<div class="card">
<h2>User Profile Claims</h2>
<table class="info-table">
<?php foreach ($user as $key => $value): ?>
<tr>
<td class="label"><?= htmlspecialchars($key) ?></td>
<td class="value"><?= htmlspecialchars(is_array($value) ? json_encode($value) : (string)$value) ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
<div class="card">
<h2>ID Token</h2>
<pre class="token-box"><?= htmlspecialchars($credentials->idToken ?? 'N/A') ?></pre>
</div>
<div class="card">
<h2>Access Token</h2>
<pre class="token-box"><?= htmlspecialchars($credentials->accessToken ?? 'N/A') ?></pre>
<table class="info-table">
<tr>
<td class="label">Expires</td>
<td class="value"><?= $credentials->accessTokenExpiration ? date('Y-m-d H:i:s', $credentials->accessTokenExpiration) . ' (' . ($credentials->accessTokenExpired ? 'EXPIRED' : 'valid') . ')' : 'N/A' ?></td>
</tr>
<tr>
<td class="label">Scopes</td>
<td class="value"><?= htmlspecialchars(implode(', ', $credentials->accessTokenScope ?? [])) ?></td>
</tr>
</table>
</div>
<?php if ($credentials->refreshToken): ?>
<div class="card">
<h2>Refresh Token</h2>
<pre class="token-box"><?= htmlspecialchars($credentials->refreshToken) ?></pre>
</div>
<?php endif; ?>
</div>
</body>
</html>
getCredentials()はユーザーのセッションデータを返します。ログインしていない場合はnullを返します。プロフィールページには、開発中の確認用としてすべてのユーザークレームとトークンが表示されます。
11. ログアウトルートを追加する
routes/logout.phpを作成します。
<?php
header('Location: ' . $auth0->logout(returnUri: 'http://localhost:3000'));
exit;
logout()はAuth0のログアウトURLを返します。ユーザーをそのURLにリダイレクトしてください。returnUriはログアウト後にAuth0がユーザーを送る先です。Allowed Logout URLsに登録されている必要があります。本番環境では実際のドメインに置き換えてください。
12. アプリをテストする
php -S localhost:3000 index.php
http://localhost:3000/loginにアクセスして、ログインフローを開始します。
よくある間違い
| 間違い | 修正方法 |
|---|---|
ソースコード内に domain、clientId、clientSecret をハードコードする | 常に環境変数から読み込みます。コードに認証情報を埋め込まないでください |
古い auth0-PHP バージョン < 8.0 を使用する | PHP 8.2 以降と SDK の v8.x を使用してください。古いバージョンでは API が異なります |
| PSR-18 HTTP クライアントをインストールせずに使用する | PSR-18 クライアント(例:guzzlehttp/guzzle)が必要です。ない場合、SDK は HTTP リクエストを送信できません |
ウェブアプリで STRATEGY_API を使用する | ウェブアプリでは、セッションベースの認証に SdkConfiguration::STRATEGY_REGULAR を使用する必要があります |
domain に https:// を含む完全な URL を渡す | domain には、https://my-tenant.us.auth0.com ではなく、my-tenant.us.auth0.com のようなドメインのみを指定します |
cookieSecret を設定し忘れる | セッションの暗号化に必要です。設定しない場合、SDK は ConfigurationException をスローします |
exchange() の前に getExchangeParameters() を確認しない | パラメーターを指定せずに exchange() を呼び出すとエラーになります。必ず先に確認してください |
| コールバックでエラーを処理しない | exchange() は失敗する可能性があります。必ず try/catch で囲んでください |
| Auth0 でアプリを SPA タイプとして作成する | サーバーサイド認証には、Regular Web Application タイプである必要があります |
| Auth0 Dashboard でコールバック URL を設定しない | http://localhost:3000/callback を Allowed Callback URLs に追加する必要があります |
$_SESSION を直接使用する | SDK は独自の暗号化された Cookie セッションを管理します。カスタム SessionStore を設定する場合を除き、$_SESSION を使用しないでください |
cookieSecure: true を設定せずにデプロイする | 本番環境では true に設定する必要があります。そうしない場合、Cookie は HTTP 経由で送信されます |
リダイレクトせずに login() または logout() を呼び出す | どちらもレスポンスではなく URL 文字列を返すため、header('Location: ...') を使用する必要があります |
| コールバックで「Network error resulted in unfulfilled request」が発生する | 実際のネットワーク問題ではなく、通常は AUTH0_CLIENT_SECRET が間違っています。.env 内の認証情報を確認してください |
主な SDK メソッド
| メソッド | シグネチャ | 目的 |
|---|---|---|
login | $auth0->login(?string $redirectUrl, ?array $params): string | 認証 URL 文字列を返します。ユーザーをその URL にリダイレクトします |
exchange | $auth0->exchange(?string $redirectUri, ?string $code, ?string $state): bool | 認証コードをトークンと交換し、セッションを確立します |
getCredentials | $auth0->getCredentials(): ?object | 現在のセッション認証情報を返します。ない場合は null を返します |
getExchangeParameters | $auth0->getExchangeParameters(): ?object | コールバックに交換パラメーターが含まれているか確認します |
logout | $auth0->logout(?string $returnUri, ?array $params): string | Auth0 のログアウト URL 文字列を返します |
renew | $auth0->renew(?array $params): self | 期限切れのアクセストークンを更新します(offline_access スコープが必要です) |
clear | $auth0->clear(bool $transient = true): self | Auth0 からログアウトせずにローカルセッションをクリアします |
認証情報オブジェクト
認証に成功すると、getCredentials() は次の内容を含むオブジェクトを返します。
$credentials = $auth0->getCredentials();
$credentials->user; // array - user profile claims
$credentials->idToken; // string - raw ID token
$credentials->accessToken; // string - access token
$credentials->refreshToken; // string|null - refresh token (requires offline_access)
$credentials->accessTokenExpiration; // int - expiration timestamp
$credentials->accessTokenExpired; // bool - whether token is expired
$credentials->accessTokenScope; // array - granted scopes
ユーザープロファイルのクレーム($credentials->user):
sub- 一意のユーザー識別子name、nickname、pictureemail、email_verifiedgiven_name、family_nameupdated_at、locale
関連スキル
auth0-php-api- JWT Bearer トークン検証で PHP API を保護しますauth0-quickstart- Auth0 の基本設定とフレームワークの検出auth0-cli- ターミナルから Auth0 リソースを管理しますauth0-mfa- 多要素認証を追加します
クイックリファレンス
ウェブアプリ用の SdkConfiguration:
$configuration = new SdkConfiguration(
strategy: SdkConfiguration::STRATEGY_REGULAR, // required
domain: $_ENV['AUTH0_DOMAIN'], // required
clientId: $_ENV['AUTH0_CLIENT_ID'], // required
clientSecret: $_ENV['AUTH0_CLIENT_SECRET'], // required
cookieSecret: $_ENV['AUTH0_COOKIE_SECRET'], // required
redirectUri: $_ENV['AUTH0_REDIRECT_URI'], // required
scope: ['openid', 'profile', 'email'], // recommended
);
ルート保護パターン:
$credentials = $auth0->getCredentials();
if (null === $credentials) {
header('Location: /login');
exit;
}
環境変数:
AUTH0_DOMAIN- Auth0 テナントのドメイン(例:tenant.us.auth0.com)AUTH0_CLIENT_ID- アプリケーションのクライアント IDAUTH0_CLIENT_SECRET- アプリケーションのクライアントシークレットAUTH0_COOKIE_SECRET- 暗号化シークレットキー(生成方法:openssl rand -hex 32)AUTH0_REDIRECT_URI- コールバック URL(例:http://localhost:3000/callback)
詳細ドキュメント
- セットアップガイド - 自動セットアップスクリプト、環境設定、Auth0 CLI の使用方法
- インテグレーションガイド - 保護されたルート、API の呼び出し、セッション管理、エラー処理
- API リファレンス - Auth0 SDK API の全仕様、設定オプション、セッションストレージ、セキュリティ