Skip to content

Commit 7415957

Browse files
[11.x] Support prompting login when redirecting for authorization (#1577)
* Support prompting login when redirecting for authorization * use fragment on redirect uri for implicit grant * bind StatefulGuard * formatting Co-authored-by: Taylor Otwell <[email protected]>
1 parent 3a4d6e5 commit 7415957

File tree

4 files changed

+204
-14
lines changed

4 files changed

+204
-14
lines changed

routes/web.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@
88
'middleware' => 'throttle',
99
]);
1010

11+
Route::get('/authorize', [
12+
'uses' => 'AuthorizationController@authorize',
13+
'as' => 'authorizations.authorize',
14+
'middleware' => 'web',
15+
]);
16+
1117
Route::middleware(['web', 'auth'])->group(function () {
1218
Route::post('/token/refresh', [
1319
'uses' => 'TransientTokenController@refresh',
1420
'as' => 'token.refresh',
1521
]);
1622

17-
Route::get('/authorize', [
18-
'uses' => 'AuthorizationController@authorize',
19-
'as' => 'authorizations.authorize',
20-
]);
21-
2223
Route::post('/authorize', [
2324
'uses' => 'ApproveAuthorizationController@approve',
2425
'as' => 'authorizations.approve',

src/Http/Controllers/AuthorizationController.php

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

33
namespace Laravel\Passport\Http\Controllers;
44

5+
use Illuminate\Auth\AuthenticationException;
6+
use Illuminate\Contracts\Auth\StatefulGuard;
57
use Illuminate\Contracts\Routing\ResponseFactory;
68
use Illuminate\Http\Request;
79
use Illuminate\Support\Str;
@@ -10,6 +12,7 @@
1012
use Laravel\Passport\Passport;
1113
use Laravel\Passport\TokenRepository;
1214
use League\OAuth2\Server\AuthorizationServer;
15+
use League\OAuth2\Server\Exception\OAuthServerException;
1316
use Nyholm\Psr7\Response as Psr7Response;
1417
use Psr\Http\Message\ServerRequestInterface;
1518

@@ -31,17 +34,28 @@ class AuthorizationController
3134
*/
3235
protected $response;
3336

37+
/**
38+
* The guard implementation.
39+
*
40+
* @var \Illuminate\Contracts\Auth\StatefulGuard
41+
*/
42+
protected $guard;
43+
3444
/**
3545
* Create a new controller instance.
3646
*
3747
* @param \League\OAuth2\Server\AuthorizationServer $server
3848
* @param \Illuminate\Contracts\Routing\ResponseFactory $response
49+
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
3950
* @return void
4051
*/
41-
public function __construct(AuthorizationServer $server, ResponseFactory $response)
52+
public function __construct(AuthorizationServer $server,
53+
ResponseFactory $response,
54+
StatefulGuard $guard)
4255
{
4356
$this->server = $server;
4457
$this->response = $response;
58+
$this->guard = $guard;
4559
}
4660

4761
/**
@@ -62,6 +76,23 @@ public function authorize(ServerRequestInterface $psrRequest,
6276
return $this->server->validateAuthorizationRequest($psrRequest);
6377
});
6478

79+
if ($this->guard->guest()) {
80+
return $request->get('prompt') === 'none'
81+
? $this->denyRequest($authRequest)
82+
: $this->promptForLogin($request);
83+
}
84+
85+
if ($request->get('prompt') === 'login' &&
86+
! $request->session()->get('promptedForLogin', false)) {
87+
$this->guard->logout();
88+
$request->session()->invalidate();
89+
$request->session()->regenerateToken();
90+
91+
return $this->promptForLogin($request);
92+
}
93+
94+
$request->session()->forget('promptedForLogin');
95+
6596
$scopes = $this->parseScopes($authRequest);
6697
$user = $request->user();
6798
$client = $clients->find($authRequest->getClient()->getIdentifier());
@@ -142,11 +173,26 @@ protected function approveRequest($authRequest, $user)
142173
* Deny the authorization request.
143174
*
144175
* @param \League\OAuth2\Server\RequestTypes\AuthorizationRequest $authRequest
145-
* @param \Illuminate\Database\Eloquent\Model $user
176+
* @param \Illuminate\Database\Eloquent\Model|null $user
146177
* @return \Illuminate\Http\Response
147178
*/
148-
protected function denyRequest($authRequest, $user)
179+
protected function denyRequest($authRequest, $user = null)
149180
{
181+
if (is_null($user)) {
182+
$uri = $authRequest->getRedirectUri()
183+
?? (is_array($authRequest->getClient()->getRedirectUri())
184+
? $authRequest->getClient()->getRedirectUri()[0]
185+
: $authRequest->getClient()->getRedirectUri());
186+
187+
$separator = $authRequest->getGrantTypeId() === 'implicit' ? '#' : '?';
188+
189+
$uri = $uri.(str_contains($uri, $separator) ? '&' : $separator).'state='.$authRequest->getState();
190+
191+
return $this->withErrorHandling(function () use ($uri) {
192+
throw OAuthServerException::accessDenied('Unauthenticated', $uri);
193+
});
194+
}
195+
150196
$authRequest->setUser(new User($user->getAuthIdentifier()));
151197

152198
$authRequest->setAuthorizationApproved(false);
@@ -157,4 +203,18 @@ protected function denyRequest($authRequest, $user)
157203
);
158204
});
159205
}
206+
207+
/**
208+
* Prompt the user to login by throwing an AuthenticationException.
209+
*
210+
* @param \Illuminate\Http\Request $request
211+
*
212+
* @throws \Illuminate\Auth\AuthenticationException
213+
*/
214+
protected function promptForLogin($request)
215+
{
216+
$request->session()->put('promptedForLogin', true);
217+
218+
throw new AuthenticationException;
219+
}
160220
}

src/PassportServiceProvider.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use DateInterval;
66
use Illuminate\Auth\Events\Logout;
77
use Illuminate\Config\Repository as Config;
8+
use Illuminate\Contracts\Auth\StatefulGuard;
89
use Illuminate\Support\Facades\Auth;
910
use Illuminate\Support\Facades\Cookie;
1011
use Illuminate\Support\Facades\Event;
@@ -14,6 +15,7 @@
1415
use Laravel\Passport\Bridge\PersonalAccessGrant;
1516
use Laravel\Passport\Bridge\RefreshTokenRepository;
1617
use Laravel\Passport\Guards\TokenGuard;
18+
use Laravel\Passport\Http\Controllers\AuthorizationController;
1719
use Lcobucci\JWT\Configuration;
1820
use Lcobucci\JWT\Parser;
1921
use League\OAuth2\Server\AuthorizationServer;
@@ -134,6 +136,10 @@ public function register()
134136

135137
Passport::setClientUuids($this->app->make(Config::class)->get('passport.client_uuids', false));
136138

139+
$this->app->when(AuthorizationController::class)
140+
->needs(StatefulGuard::class)
141+
->give(fn () => Auth::guard(config('passport.guard', null)));
142+
137143
$this->registerAuthorizationServer();
138144
$this->registerClientRepository();
139145
$this->registerJWTParser();

0 commit comments

Comments
 (0)