Skip to content

Commit 828ae5a

Browse files
committed
Bump to 7.11.0
1 parent 137f68b commit 828ae5a

File tree

81 files changed

+1368
-616
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1368
-616
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# Changelog
22

3+
## [7.11.0](https://github.com/auth0/laravel-auth0/tree/7.10.1) (2023-08-08)
4+
5+
### Added
6+
7+
- Significant performance improvements by eliminating redundant user queries.
8+
- Compatibility support for [Laravel Telescope](https://laravel.com/docs/telescope). See [docs/Telescope.md](./docs/Telescope.md) for more information.
9+
- A refactored Events API has been introduced. See [docs/Events.md](./docs/Events.md) for more information.
10+
- `AUTH0_SESSION_STORAGE` and `AUTH0_TRANSIENT_STORAGE` now support a `cookie` value to enable the native Auth0-PHP SDK cookie session handler. See [docs/Cookies.md](./docs/Cookies.md) for more information.
11+
12+
### Fixed
13+
14+
- Addressed an issue where, under certain circumstances, the first user authentication attempt after a session invalidation could fail.
15+
16+
### Changed
17+
18+
- Session regeneration/invalidation has been refactored.
19+
- Discarded sessions are now deleted when they are invalidated by the SDK, rather than wait for Laravel to garbage collect.
20+
- Session storage has been refactored. Session data is now stored as a JSON array in a single `auth0_session` entry in the Laravel session store, rather than in multiple keys.
21+
22+
### Documentation
23+
24+
- A demonstration Eloquent user model and repository implementation has been added to [docs/Eloquent.md](./docs/Eloquent.md).
25+
- A new [docs/Sessions.md](./docs/Sessions.md) document has been added for guidance on the various session driver options available.
26+
327
## [7.10.1](https://github.com/auth0/laravel-auth0/tree/7.10.1) (2023-08-07)
428

529
### Fixed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,11 +356,18 @@ All the SDK's Management API methods are [documented here](./docs/Management.md)
356356
357357
- [Installation](./docs/Installation.md) — Installing the SDK and generating configuration files.
358358
- [Configuration](./docs/Configuration.md) — Configuring the SDK using JSON files or environment variables.
359-
- [Management](./docs/Management.md) — Using the SDK to call the [Management API](https://auth0.com/docs/api/management/v2).
360-
- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent).
359+
- [Sessions](./docs/Sessions.md) — Guidance on deciding which Laravel Session API driver to use.
360+
- [Cookies](./docs/Cookies.md) — Important notes about using Laravel's Cookie session driver, and alternative options.
361+
- [Management API](./docs/Management.md) — Using the SDK to work with the [Auth0 Management API](https://auth0.com/docs/api/management/v2).
362+
- [Users](./docs/Users.md) — Extending the SDK to support persistent storage and [Eloquent](https://laravel.com/docs/eloquent) models.
361363
- [Events](./docs/Events.md) — Hooking into SDK [events](https://laravel.com/docs/events) to respond to specific actions.
362364
- [Deployment](./docs/Deployment.md) — Deploying your application to production.
363-
- [Octane](./docs/Octane.md) — We do not support using the SDK with [Octane](https://laravel.com/docs/octane) at this time.
365+
366+
You may find the following integration guidance useful:
367+
368+
- [Laravel Eloquent](./docs/Eloquent.md) — [Eloquent ORM](https://laravel.com/docs/eloquent) is supported.
369+
- [Laravel Octane](./docs/Octane.md) — [Octane](https://laravel.com/docs/octane) is not supported at this time.
370+
- [Laravel Telescope](./docs/Telescope.md) — [Telescope](https://laravel.com/docs/telescope) is compatible as of SDK v7.11.0.
364371
365372
You may also find the following resources helpful:
366373

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
"pest:coverage": "@php vendor/bin/pest --coverage --parallel --no-progress",
115115
"pest:debug": "@php vendor/bin/pest --fail-on-risky --stop-on-defect",
116116
"pest:profile": "@php vendor/bin/pest --profile",
117-
"pest": "@php vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --coverage --parallel --min=95",
117+
"pest": "@php vendor/bin/pest --order-by random --fail-on-risky --stop-on-defect --parallel",
118118
"phpcs:fix": "@php vendor/bin/php-cs-fixer fix",
119119
"phpcs": "@php vendor/bin/php-cs-fixer fix --dry-run --diff",
120120
"phpstan": "@php vendor/bin/phpstan analyze",

docs/Configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ The following parameters used in this example are of note:
268268
- For Laravel applications, this should always be set to `regular`.
269269
- `--auth-method` - This represents the 'Token Endpoint Authentication Method' used for authentication.
270270
- For Laravel applications, this should always be set to `post`.
271-
- `--callbacks` - The callback URLs to use for authentication.
271+
- `--callbacks` - The callback URLs to use for authentication.
272272
- In development, this should be set to `http://localhost:8000/callback` or as appropriate.
273273
- In production, adjust this value to match your application's Internet-accessible URL for its`/callback`` route.
274274
- This value can be a comma-separated list of URLs.

docs/Cookies.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Cookies
2+
3+
We strongly recommend using the `database` or `redis` session drivers, but realize this is not always a viable option for all developers or use cases. The Auth0 Laravel SDK supports cookies for storing authentication state, but there are notable drawbacks to be aware of.
4+
5+
## Laravel's Cookie Session Driver
6+
7+
As noted in our [sessions documentation](./Sessions.md), Laravel's `cookie` session driver is not a reliable option for production applications as it suffers from a number of notable drawbacks:
8+
9+
- Browsers impose a size limit of 4 KB on individual cookies, which can quickly be exceeded by storing session data.
10+
- Laravel's cookie driver unfortunately does not "chunk" (split up) larger cookies into multiple cookies, so it is impossible to store more than the noted 4 KB of total session data.
11+
- Most web servers and load balancers require additional configuration to accept and deliver larger cookie headers.
12+
13+
## Auth0 PHP SDK's Custom Cookie Session Handler
14+
15+
The underlying [Auth0 PHP SDK](https://github.com/auth0/auth0-PHP) (which the Auth0 Laravel SDK is built upon) includes a powerful custom cookie session handler that supports chunking of larger cookies. This approach will enable you to securely and reliably store larger authentication states for your users.
16+
17+
It is important to note that this approach is incompatible with [Octane](./Octane.md) due to the way it delivers cookie headers.
18+
19+
To enable this feature, assign a `cookie` string value to the `AUTH0_SESSION_STORAGE` and `AUTH0_TRANSIENT_STORAGE` environment variables (or your `.env` file.)
20+
21+
```ini
22+
# Persistent session data:
23+
AUTH0_SESSION_STORAGE=cookie
24+
25+
# Temporary session data (used only during authentication):
26+
AUTH0_TRANSIENT_STORAGE=cookie
27+
```
28+
29+
This will override the SDK's default behavior of using the Laravel Sessions API, and instead use the integrated Auth0 PHP SDK's custom cookie session handler. Please note:
30+
31+
- When this feature is enabled, all properties of cookie storage (like `sameSite`, `secure`, and so forth) must be configured independently. This approach does not use Laravel's settings. Please refer to the [Auth0 PHP SDK's documentation](https://github.com/auth0/auth0-PHP) for guidance on how to configure these.
32+
- By default your Laravel application's `APP_KEY` will be used to encrypt the cookie data. You can change this by assigning the `AUTH0_COOKIE_SECRET` environment variable (or your `.env` file) a string. If you do this, please ensure you are using an adequately long secure secret.
33+
- Please ensure your server is configured to deliver and accept cookies prefixed with `auth0_session_` and `auth0_transient_` followed by a series of numbers (beginning with 0). These are the divided content body of the authenticated session data.
34+
35+
### Increasing Server Cookies Header Sizes
36+
37+
You may need to configure your web server or load balancer to accept and deliver larger cookie headers. For example, if you are using Nginx you will need to set the `large_client_header_buffers` directive to a value greater than the default of 4 KB.
38+
39+
```nginx
40+
large_client_header_buffers 4 16k;
41+
```
42+
43+
Please refer to your web server or load balancer's documentation for more information.
44+
45+
### Reminder on Octane Compatibility
46+
47+
As noted above, the Auth0 PHP SDK's custom cookie session handler is incompatible with [Octane](./Octane.md) due to the way it delivers cookie headers. If you are using Octane, you must use the Laravel Sessions API with a `database` or `redis` driver.

docs/Eloquent.md

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# Laravel Eloquent
2+
3+
By default, the SDK does not include any Eloquent models or database support. You can adapt the SDK to your application's needs by adding your own Eloquent models and database support.
4+
5+
## Creating a User Model
6+
7+
Begin by creating a new Eloquent model class. You can use the `make:model` Artisan command to do this. Laravel ships with default user model named `User`, so we'll use the `--force` flag to overwrite it with our custom one.
8+
9+
Please ensure you have a backup of your existing `User` model before running this command, as it will overwrite your existing model.
10+
11+
```bash
12+
php artisan make:model User --force
13+
```
14+
15+
Next, open your `app/Models/User.php` file and modify it match the following example. Notably, we'll add a support for a new `auth0` attribute. This attribute will be used to store the user's Auth0 ID, which is used to uniquely identify the user in Auth0.
16+
17+
```php
18+
<?php
19+
20+
declare(strict_types=1);
21+
22+
namespace App\Models;
23+
24+
use Illuminate\Auth\Authenticatable;
25+
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
26+
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
27+
use Illuminate\Database\Eloquent\Factories\HasFactory;
28+
use Illuminate\Database\Eloquent\Model;
29+
use Illuminate\Foundation\Auth\Access\Authorizable;
30+
31+
class User extends Model implements
32+
AuthenticatableContract,
33+
AuthorizableContract
34+
{
35+
use Authenticatable,
36+
Authorizable,
37+
HasFactory;
38+
39+
protected $fillable = [
40+
'auth0',
41+
'name',
42+
'email',
43+
'email_verified',
44+
'password',
45+
];
46+
47+
protected $hidden = [
48+
'password',
49+
'remember_token',
50+
];
51+
52+
protected $casts = [
53+
'email_verified_at' => 'datetime',
54+
];
55+
}
56+
```
57+
58+
Next, create a migration to update your application's `users` table schema to support these changes. Create a new migration file:
59+
60+
```bash
61+
php artisan make:migration update_users_table --table=users
62+
```
63+
64+
Openly the newly created migration file (found under `database/migrations` and ending in `update_users_table.php`) and update to match the following example:
65+
66+
```php
67+
<?php
68+
69+
declare(strict_types=1);
70+
71+
use Illuminate\Database\Migrations\Migration;
72+
use Illuminate\Database\Schema\Blueprint;
73+
use Illuminate\Support\Facades\Schema;
74+
75+
return new class extends Migration
76+
{
77+
public function up()
78+
{
79+
Schema::table('users', function (Blueprint $table) {
80+
$table->string('auth0')->nullable();
81+
$table->boolean('email_verified')->default(false);
82+
83+
$table->unique('auth0', 'users_auth0_unique');
84+
});
85+
}
86+
87+
public function down()
88+
{
89+
Schema::table('users', function (Blueprint $table) {
90+
$table->dropUnique('users_auth0_unique');
91+
92+
$table->dropColumn('auth0');
93+
$table->dropColumn('email_verified');
94+
});
95+
}
96+
};
97+
98+
```
99+
100+
Now run the migration:
101+
102+
```bash
103+
php artisan migrate
104+
```
105+
106+
## Creating a User Repository
107+
108+
You'll need to create a new user repository class to handle the creation and retrieval of your Eloquent user models from your database table.
109+
110+
Create a new repository class in your application at `app/Repositories/UserRepository.php`, and update it to match the following example:
111+
112+
```php
113+
<?php
114+
115+
declare(strict_types=1);
116+
117+
namespace App\Repositories;
118+
119+
use App\Models\User;
120+
use Auth0\Laravel\{UserRepositoryAbstract, UserRepositoryContract};
121+
use Illuminate\Contracts\Auth\Authenticatable;
122+
use Illuminate\Support\Facades\Cache;
123+
use Illuminate\Support\Facades\Hash;
124+
use Illuminate\Support\Str;
125+
126+
final class UserRepository extends UserRepositoryAbstract implements UserRepositoryContract
127+
{
128+
public function fromAccessToken(array $user): ?Authenticatable
129+
{
130+
/*
131+
$user = [ // Example of a decoded access token
132+
"iss" => "https://example.auth0.com/",
133+
"aud" => "https://api.example.com/calendar/v1/",
134+
"sub" => "auth0|123456",
135+
"exp" => 1458872196,
136+
"iat" => 1458785796,
137+
"scope" => "read write",
138+
];
139+
*/
140+
141+
$identifier = $user['sub'] ?? $user['auth0'] ?? null;
142+
143+
if (null === $identifier) {
144+
return null;
145+
}
146+
147+
return User::where('auth0', $identifier)->first();
148+
}
149+
150+
public function fromSession(array $user): ?Authenticatable
151+
{
152+
/*
153+
$user = [ // Example of a decoded ID token
154+
"iss" => "http://example.auth0.com",
155+
"aud" => "client_id",
156+
"sub" => "auth0|123456",
157+
"exp" => 1458872196,
158+
"iat" => 1458785796,
159+
"name" => "Jane Doe",
160+
"email" => "[email protected]",
161+
];
162+
*/
163+
164+
// Determine the Auth0 identifier for the user from the $user array.
165+
$identifier = $user['sub'] ?? $user['auth0'] ?? null;
166+
167+
// Collect relevant user profile information from the $user array for use later.
168+
$profile = [
169+
'auth0' => $identifier,
170+
'name' => $user['name'] ?? '',
171+
'email' => $user['email'] ?? '',
172+
'email_verified' => in_array($user['email_verified'], [1, true], true),
173+
];
174+
175+
// Check if a cache of the user exists in memory to avoid unnecessary database queries.
176+
$cached = $this->withoutRecording(fn () => Cache::get('auth0_user_' . $identifier));
177+
178+
if ($cached) {
179+
// Immediately return a cached user if one exists.
180+
return $cached;
181+
}
182+
183+
$user = null;
184+
185+
// Check if the user exists in the database by Auth0 identifier.
186+
if (null !== $identifier) {
187+
$user = User::where('auth0', $identifier)->first();
188+
}
189+
190+
// Optional: if the user does not exist in the database by Auth0 identifier, you could fallback to matching by email.
191+
if (null === $user && isset($user['email'])) {
192+
$user = User::where('email', $user['email'])->first();
193+
}
194+
195+
// If a user was found, check if any updates to the local record are required.
196+
if (null !== $user) {
197+
$updates = [];
198+
199+
if ($user->auth0 !== $profile['auth0']) {
200+
$updates['auth0'] = $profile['auth0'];
201+
}
202+
203+
if ($user->name !== $profile['name']) {
204+
$updates['name'] = $profile['name'];
205+
}
206+
207+
if ($user->email !== $profile['email']) {
208+
$updates['email'] = $profile['email'];
209+
}
210+
211+
$emailVerified = in_array($user->email_verified, [1, true], true);
212+
213+
if ($emailVerified !== $profile['email_verified']) {
214+
$updates['email_verified'] = $profile['email_verified'];
215+
}
216+
217+
if ([] !== $updates) {
218+
$user->update($updates);
219+
$user->save();
220+
}
221+
222+
if ([] === $updates && null !== $cached) {
223+
return $user;
224+
}
225+
}
226+
227+
if (null === $user) {
228+
// Local password column is not necessary or used by Auth0 authentication, but may be expected by some applications/packages.
229+
$profile['password'] = Hash::make(Str::random(32));
230+
231+
// Create the user.
232+
$user = User::create($profile);
233+
}
234+
235+
// Cache the user for 30 seconds.
236+
$this->withoutRecording(fn () => Cache::put('auth0_user_' . $identifier, $user, 30));
237+
238+
return $user;
239+
}
240+
241+
/**
242+
* Workaround for Laravel Telescope potentially causing an infinite loop.
243+
* @link https://github.com/auth0/laravel-auth0/tree/main/docs/Telescope.md
244+
*
245+
* @param callable $callback
246+
*/
247+
private function withoutRecording($callback): mixed
248+
{
249+
$telescope = '\Laravel\Telescope\Telescope';
250+
251+
if (class_exists($telescope)) {
252+
return "$telescope"::withoutRecording($callback);
253+
}
254+
255+
return call_user_func($callback);
256+
}
257+
}
258+
```
259+
260+
Finally, update your application's `config/auth.php` file to configure the SDK to query your new user provider during authentication requests.
261+
262+
```php
263+
'providers' => [
264+
'auth0-provider' => [
265+
'driver' => 'auth0.provider',
266+
'repository' => \App\Repositories\UserRepository::class,
267+
],
268+
],
269+
```

docs/Installation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
- [Create a Laravel Application](#create-a-laravel-application)
88
- [Install the SDK](#install-the-sdk-1)
99
- [Install the CLI](#install-the-cli)
10-
- [Authenticate the CLI](#authenticate-the-cli)
10+
- [Authenticate the CLI](#authenticate-the-cli)
1111
- [Configure the SDK](#configure-the-sdk)
1212
- [Using JSON (Recommended)](#using-json-recommended)
1313
- [Using Environment Variables](#using-environment-variables)

0 commit comments

Comments
 (0)