npx skills add ...
npx skills add auth0/agent-skills --skill auth0-php
Use when adding session-based login, logout, or user profile to a PHP web application. Integrates auth0/auth0-php — use even if the user says "add login to my PHP app".
npx skills add auth0/agent-skills --skill auth0-php
Add login, logout, and user profile to a PHP web application using auth0/auth0-php.
mbstring, openssl, jsonauth0-quickstart skill firstauth0-php-api for stateless API token validationauth0/laravel-auth0auth0/symfonyauth0-react, auth0-vue, or auth0-angular for client-side authauth0-nextjs which handles both client and serverauth0-express or auth0-fastify for session-based authauth0/auth0-php - The Auth0 SDKvlucas/phpdotenv - Load .env files into $_ENVguzzlehttp/guzzle + guzzlehttp/psr7 - PSR-18 HTTP client required by the SDKCreate .env:
AUTH0_DOMAIN is your Auth0 tenant domain (without https://). AUTH0_CLIENT_ID and AUTH0_CLIENT_SECRET come from your Auth0 Application settings. AUTH0_COOKIE_SECRET is used for encrypting session cookies - generate with openssl rand -hex 32.
In your Auth0 Application settings:
http://localhost:3000/callbackhttp://localhost:3000Create auth0.php to initialize the SDK:
Create one Auth0 instance and reuse it. Never hardcode credentials - always use environment variables.
How this works: The SDK encrypts session data (tokens, user profile) using AES-256-GCM with a key derived from cookieSecret via HKDF-SHA256. Session data is stored in an encrypted cookie by default - no server-side database required.
Create index.php as a simple front controller. Create the routes/ directory first:
The static file handler for /style.css is placed before require 'auth0.php' so stylesheets load without initializing the SDK.
Create style.css:
Create routes/home.php:
Create routes/login.php:
login() returns a URL string pointing to Auth0's Universal Login page. You must redirect the user to it.
Create routes/callback.php:
getExchangeParameters() checks if the callback contains authorization code parameters. exchange() exchanges the code for tokens and establishes the session. Always wrap in try/catch since the token exchange can fail (e.g. expired code, CSRF mismatch).
Create routes/profile.php:
getCredentials() returns the user's session data, or null if not logged in. The profile page displays all user claims and tokens for verification during development.
Create routes/logout.php:
logout() returns the Auth0 logout URL. Redirect the user to it. The returnUri is where Auth0 sends the user after logout - it must be listed in Allowed Logout URLs. In production, replace with your actual domain.
Visit http://localhost:3000/login to start the login flow.
| Mistake | Fix |
|---|---|
Hardcoding domain, clientId, or clientSecret in source | Always read from environment variables - never embed credentials in code |
Using an old auth0-PHP version < 8.0 | Require PHP 8.2+ and v8.x of the SDK; older versions have different APIs |
| Installing without a PSR-18 HTTP client | Must have a PSR-18 client (e.g. guzzlehttp/guzzle) or the SDK cannot make HTTP requests |
Using STRATEGY_API for a web app | Web apps must use SdkConfiguration::STRATEGY_REGULAR for session-based auth |
Passing domain as full URL with https:// | domain should be the bare domain, e.g. my-tenant.us.auth0.com, not https://my-tenant.us.auth0.com |
Forgetting cookieSecret | Required for session encryption - without it, the SDK throws a ConfigurationException |
Not checking getExchangeParameters() before exchange() | Calling exchange() without parameters causes errors; always check first |
| Not handling errors in callback | exchange() can fail - always wrap in try/catch |
| Created app as SPA type in Auth0 | Must be Regular Web Application type for server-side auth |
| Not configuring callback URL in Auth0 Dashboard | Must add http://localhost:3000/callback to Allowed Callback URLs |
Using $_SESSION directly | The SDK manages its own encrypted cookie session - do not use $_SESSION unless you configure a custom SessionStore |
Deploying without cookieSecure: true | Must set to true in production - cookies are sent over HTTP otherwise |
Calling login() or logout() without redirecting | Both return URL strings, not responses - must use header('Location: ...') |
| "Network error resulted in unfulfilled request" on callback | Usually means AUTH0_CLIENT_SECRET is wrong, not an actual network issue - verify your credentials in .env |
| Method | Signature | Purpose |
|---|---|---|
login | $auth0->login(?string $redirectUrl, ?array $params): string | Returns authorization URL string - redirect user to it |
exchange | $auth0->exchange(?string $redirectUri, ?string $code, ?string $state): bool | Exchanges authorization code for tokens, establishes session |
getCredentials | $auth0->getCredentials(): ?object | Returns current session credentials or null |
getExchangeParameters | $auth0->getExchangeParameters(): ?object | Checks if callback contains exchange parameters |
logout | $auth0->logout(?string $returnUri, ?array $params): string | Returns Auth0 logout URL string |
renew | $auth0->renew(?array $params): self | Refreshes expired access token (requires offline_access scope) |
clear | $auth0->clear(bool $transient = true): self | Clears local session without Auth0 logout |
After successful authentication, getCredentials() returns an object with:
User profile claims ($credentials->user):
sub - unique user identifiername, nickname, pictureemail, email_verifiedgiven_name, family_nameupdated_at, localeauth0-php-api - For protecting PHP APIs with JWT Bearer token validationauth0-quickstart - Basic Auth0 setup and framework detectionauth0-cli - Manage Auth0 resources from the terminalauth0-mfa - Add Multi-Factor AuthenticationSdkConfiguration for web apps:
Route protection pattern:
Environment variables:
AUTH0_DOMAIN - your Auth0 tenant domain (e.g. tenant.us.auth0.com)AUTH0_CLIENT_ID - your Application's client IDAUTH0_CLIENT_SECRET - your Application's client secretAUTH0_COOKIE_SECRET - encryption secret key (generate: openssl rand -hex 32)AUTH0_REDIRECT_URI - callback URL (e.g. http://localhost:3000/callback)