Skip to content

Commit 59c7555

Browse files
Merge branch '13.x' into 13.x-device-code-grant
2 parents 4341491 + 61644b3 commit 59c7555

18 files changed

+320
-224
lines changed

database/factories/ClientFactory.php

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ public function definition()
3232
'user_id' => null,
3333
'name' => $this->faker->company(),
3434
'secret' => Str::random(40),
35-
'redirect' => $this->faker->url(),
36-
'personal_access_client' => false,
37-
'password_client' => false,
35+
'redirect_uris' => [$this->faker->url()],
36+
'grant_types' => ['authorization_code', 'refresh_token'],
3837
'revoked' => false,
3938
];
4039
}
@@ -47,8 +46,7 @@ public function definition()
4746
public function asPasswordClient()
4847
{
4948
return $this->state([
50-
'personal_access_client' => false,
51-
'password_client' => true,
49+
'grant_types' => ['password', 'refresh_token'],
5250
]);
5351
}
5452

@@ -60,8 +58,7 @@ public function asPasswordClient()
6058
public function asPersonalAccessTokenClient()
6159
{
6260
return $this->state([
63-
'personal_access_client' => true,
64-
'password_client' => false,
61+
'grant_types' => ['personal_access'],
6562
]);
6663
}
6764

@@ -73,8 +70,7 @@ public function asPersonalAccessTokenClient()
7370
public function asClientCredentials()
7471
{
7572
return $this->state([
76-
'personal_access_client' => false,
77-
'password_client' => false,
73+
'grant_types' => ['client_credentials'],
7874
]);
7975
}
8076
}

database/migrations/2016_06_01_000004_create_oauth_clients_table.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ public function up(): void
1717
$table->string('name');
1818
$table->string('secret')->nullable();
1919
$table->string('provider')->nullable();
20-
$table->text('redirect');
21-
$table->boolean('personal_access_client');
22-
$table->boolean('password_client');
20+
$table->text('redirect_uris');
21+
$table->text('grant_types');
2322
$table->boolean('revoked');
2423
$table->timestamps();
2524
});

src/Bridge/Client.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class Client implements ClientEntityInterface
2121
public function __construct(
2222
string $identifier,
2323
?string $name = null,
24-
?string $redirectUri = null,
24+
array $redirectUri = [],
2525
bool $isConfidential = false,
2626
?string $provider = null
2727
) {
@@ -31,11 +31,8 @@ public function __construct(
3131
$this->name = $name;
3232
}
3333

34-
if (! is_null($redirectUri)) {
35-
$this->redirectUri = explode(',', $redirectUri);
36-
}
37-
3834
$this->isConfidential = $isConfidential;
35+
$this->redirectUri = $redirectUri;
3936
$this->provider = $provider;
4037
}
4138
}

src/Bridge/ClientRepository.php

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public function getClientEntity(string $clientIdentifier): ?ClientEntityInterfac
4343
return new Client(
4444
$clientIdentifier,
4545
$record->name,
46-
$record->redirect,
46+
$record->redirect_uris,
4747
$record->confidential(),
4848
$record->provider
4949
);
@@ -71,17 +71,7 @@ public function validateClient(string $clientIdentifier, ?string $clientSecret,
7171
*/
7272
protected function handlesGrant(ClientModel $record, string $grantType): bool
7373
{
74-
if (! $record->hasGrantType($grantType)) {
75-
return false;
76-
}
77-
78-
return match ($grantType) {
79-
'authorization_code' => ! $record->firstParty(),
80-
'personal_access' => $record->personal_access_client && $record->confidential(),
81-
'password' => $record->password_client,
82-
'client_credentials' => $record->confidential(),
83-
default => true,
84-
};
74+
return $record->hasGrantType($grantType);
8575
}
8676

8777
/**

src/Client.php

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Laravel\Passport;
44

5+
use Illuminate\Contracts\Auth\Authenticatable;
6+
use Illuminate\Database\Eloquent\Casts\Attribute;
57
use Illuminate\Database\Eloquent\Factories\HasFactory;
68
use Illuminate\Database\Eloquent\Model;
79
use Illuminate\Support\Facades\Hash;
@@ -44,6 +46,7 @@ class Client extends Model
4446
protected $casts = [
4547
'grant_types' => 'array',
4648
'scopes' => 'array',
49+
'redirect_uris' => 'array',
4750
'personal_access_client' => 'bool',
4851
'password_client' => 'bool',
4952
'revoked' => 'bool',
@@ -132,22 +135,38 @@ public function setSecretAttribute($value)
132135
$this->attributes['secret'] = is_null($value) ? $value : Hash::make($value);
133136
}
134137

138+
/**
139+
* Get the client's redirect URIs.
140+
*/
141+
protected function redirectUris(): Attribute
142+
{
143+
return Attribute::make(
144+
get: function (?string $value, array $attributes) {
145+
if (isset($value)) {
146+
return $this->fromJson($value);
147+
}
148+
149+
return empty($attributes['redirect']) ? [] : explode(',', $attributes['redirect']);
150+
},
151+
);
152+
}
153+
135154
/**
136155
* Determine if the client is a "first party" client.
137156
*
138157
* @return bool
139158
*/
140159
public function firstParty()
141160
{
142-
return $this->personal_access_client || $this->password_client;
161+
return $this->hasGrantType('personal_access') || $this->hasGrantType('password');
143162
}
144163

145164
/**
146165
* Determine if the client should skip the authorization prompt.
147166
*
148-
* @return bool
167+
* @param \Laravel\Passport\Scope[] $scopes
149168
*/
150-
public function skipsAuthorization()
169+
public function skipsAuthorization(Authenticatable $user, array $scopes): bool
151170
{
152171
return false;
153172
}
@@ -160,11 +179,17 @@ public function skipsAuthorization()
160179
*/
161180
public function hasGrantType($grantType)
162181
{
163-
if (! isset($this->attributes['grant_types']) || ! is_array($this->grant_types)) {
164-
return true;
182+
if (isset($this->attributes['grant_types']) && is_array($this->grant_types)) {
183+
return in_array($grantType, $this->grant_types);
165184
}
166185

167-
return in_array($grantType, $this->grant_types);
186+
return match ($grantType) {
187+
'authorization_code' => ! $this->personal_access_client && ! $this->password_client,
188+
'personal_access' => $this->personal_access_client && $this->confidential(),
189+
'password' => $this->password_client,
190+
'client_credentials' => $this->confidential(),
191+
default => true,
192+
};
168193
}
169194

170195
/**

src/ClientRepository.php

Lines changed: 80 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Laravel\Passport;
44

5+
use Illuminate\Contracts\Auth\Authenticatable;
56
use Illuminate\Support\Str;
67

78
class ClientRepository
@@ -78,75 +79,110 @@ public function activeForUser($userId)
7879
/**
7980
* Store a new client.
8081
*
81-
* @param int|null $userId
82-
* @param string $name
83-
* @param string $redirect
84-
* @param string|null $provider
85-
* @param bool $personalAccess
86-
* @param bool $password
87-
* @param bool $confidential
88-
* @return \Laravel\Passport\Client
82+
* @param string[] $redirectUris
83+
* @param string[] $grantTypes
8984
*/
90-
public function create($userId, $name, $redirect, $provider = null, $personalAccess = false, $password = false, $confidential = true)
91-
{
92-
$client = Passport::client()->forceFill([
93-
'user_id' => $userId,
85+
protected function create(
86+
string $name,
87+
array $grantTypes,
88+
array $redirectUris = [],
89+
?string $provider = null,
90+
bool $confidential = true,
91+
?Authenticatable $user = null
92+
): Client {
93+
$client = Passport::client();
94+
$columns = $client->getConnection()->getSchemaBuilder()->getColumnListing($client->getTable());
95+
96+
$attributes = [
9497
'name' => $name,
95-
'secret' => ($confidential || $personalAccess) ? Str::random(40) : null,
98+
'secret' => $confidential ? Str::random(40) : null,
9699
'provider' => $provider,
97-
'redirect' => $redirect,
98-
'personal_access_client' => $personalAccess,
99-
'password_client' => $password,
100100
'revoked' => false,
101-
]);
102-
103-
$client->save();
104-
105-
return $client;
101+
...(in_array('redirect_uris', $columns) ? [
102+
'redirect_uris' => $redirectUris,
103+
] : [
104+
'redirect' => implode(',', $redirectUris),
105+
]),
106+
...(in_array('grant_types', $columns) ? [
107+
'grant_types' => $grantTypes,
108+
] : [
109+
'personal_access_client' => in_array('personal_access', $grantTypes),
110+
'password_client' => in_array('password', $grantTypes),
111+
]),
112+
];
113+
114+
return $user
115+
? $user->clients()->forceCreate($attributes)
116+
: $client->forceCreate($attributes);
106117
}
107118

108119
/**
109120
* Store a new personal access token client.
110-
*
111-
* @param int|null $userId
112-
* @param string $name
113-
* @param string $redirect
114-
* @return \Laravel\Passport\Client
115121
*/
116-
public function createPersonalAccessClient($userId, $name, $redirect)
122+
public function createPersonalAccessGrantClient(string $name, ?string $provider = null): Client
117123
{
118-
return $this->create($userId, $name, $redirect, null, true);
124+
return $this->create($name, ['personal_access'], [], $provider);
119125
}
120126

121127
/**
122128
* Store a new password grant client.
129+
*/
130+
public function createPasswordGrantClient(string $name, ?string $provider = null): Client
131+
{
132+
return $this->create($name, ['password', 'refresh_token'], [], $provider);
133+
}
134+
135+
/**
136+
* Store a new client credentials grant client.
137+
*/
138+
public function createClientCredentialsGrantClient(string $name): Client
139+
{
140+
return $this->create($name, ['client_credentials']);
141+
}
142+
143+
/**
144+
* Store a new implicit grant client.
123145
*
124-
* @param int|null $userId
125-
* @param string $name
126-
* @param string $redirect
127-
* @param string|null $provider
128-
* @return \Laravel\Passport\Client
146+
* @param string[] $redirectUris
129147
*/
130-
public function createPasswordGrantClient($userId, $name, $redirect, $provider = null)
148+
public function createImplicitGrantClient(string $name, array $redirectUris): Client
131149
{
132-
return $this->create($userId, $name, $redirect, $provider, false, true);
150+
return $this->create($name, ['implicit'], $redirectUris);
151+
}
152+
153+
/**
154+
* Store a new authorization code grant client.
155+
*
156+
* @param string[] $redirectUris
157+
*/
158+
public function createAuthorizationCodeGrantClient(
159+
string $name,
160+
array $redirectUris,
161+
bool $confidential = true,
162+
?Authenticatable $user = null
163+
): Client {
164+
return $this->create(
165+
$name, ['authorization_code', 'refresh_token'], $redirectUris, null, $confidential, $user
166+
);
133167
}
134168

135169
/**
136170
* Update the given client.
137171
*
138-
* @param \Laravel\Passport\Client $client
139-
* @param string $name
140-
* @param string $redirect
141-
* @return \Laravel\Passport\Client
172+
* @param string[] $redirectUris
142173
*/
143-
public function update(Client $client, $name, $redirect)
174+
public function update(Client $client, string $name, array $redirectUris): bool
144175
{
145-
$client->forceFill([
146-
'name' => $name, 'redirect' => $redirect,
147-
])->save();
176+
$columns = $client->getConnection()->getSchemaBuilder()->getColumnListing($client->getTable());
148177

149-
return $client;
178+
return $client->forceFill([
179+
'name' => $name,
180+
...(in_array('redirect_uris', $columns) ? [
181+
'redirect_uris' => $redirectUris,
182+
] : [
183+
'redirect' => implode(',', $redirectUris),
184+
]),
185+
])->save();
150186
}
151187

152188
/**

0 commit comments

Comments
 (0)