Page MenuHomePhorge

D5730.1774835099.diff
No OneTemporary

Authored By
Unknown
Size
8 KB
Referenced Files
None
Subscribers
None

D5730.1774835099.diff

diff --git a/src/app/Http/Controllers/API/AuthController.php b/src/app/Http/Controllers/API/AuthController.php
--- a/src/app/Http/Controllers/API/AuthController.php
+++ b/src/app/Http/Controllers/API/AuthController.php
@@ -12,7 +12,9 @@
use App\Utils;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Validator;
+use Laravel\Passport\Events\AccessTokenCreated;
use Laravel\Passport\RefreshTokenRepository;
use Laravel\Passport\TokenRepository;
use League\OAuth2\Server\AuthorizationServer;
@@ -172,6 +174,8 @@
/**
* Refresh a session token.
+ *
+ * @unauthenticated
*/
public function refresh(Request $request)
{
@@ -186,7 +190,17 @@
return response()->json(['status' => 'error', 'errors' => $v->errors()], 422);
}
- $user = $request->info ? $this->guard()->user() : null;
+ $user = null;
+ if ($request->info) {
+ // We cannot use a refresh token for authentication, therefore this route
+ // is unauthenticated. This means we do not have $this->guard() available.
+ // A token refresh triggers generation of new token(s). We can bind to a Passport
+ // event that provides user identity. This seems to be the easiest way
+ // to obtain a user from the token.
+ Event::listen(static function (AccessTokenCreated $event) use (&$user) {
+ $user = User::find($event->userId);
+ });
+ }
$proxyRequest = Request::create('/oauth/token', 'POST', [
'grant_type' => 'refresh_token',
diff --git a/src/app/Http/Resources/AuthResource.php b/src/app/Http/Resources/AuthResource.php
--- a/src/app/Http/Resources/AuthResource.php
+++ b/src/app/Http/Resources/AuthResource.php
@@ -54,7 +54,7 @@
// @var DeviceInfoResource Device information (on device signup)
'device' => $this->when(isset($this->device), $this->device),
// @var int User identifier
- 'id' => $this->user_id,
+ 'id' => $this->when(isset($this->user_id), $this->user_id),
// @var UserInfoResource User information
'user' => $this->when(isset($this->userinfo), $this->userinfo),
];
diff --git a/src/resources/js/app.js b/src/resources/js/app.js
--- a/src/resources/js/app.js
+++ b/src/resources/js/app.js
@@ -156,9 +156,11 @@
// while the token is being refreshed
this.refreshTimeout = setTimeout(() => {
- axios.post('api/auth/refresh', { refresh_token: localStorage.getItem('refreshToken') }).then(response => {
- this.loginUser(response.data, false, true)
- })
+ const refresh_token = localStorage.getItem('refreshToken')
+ axios.post('api/auth/refresh', { refresh_token }, { headers: { Authorization: null } })
+ .then(response => {
+ this.loginUser(response.data, false, true)
+ })
}, timeout * 1000)
},
// Set user state to "not logged in"
diff --git a/src/resources/vue/App.vue b/src/resources/vue/App.vue
--- a/src/resources/vue/App.vue
+++ b/src/resources/vue/App.vue
@@ -31,7 +31,7 @@
if (token) {
const post = { refresh_token: localStorage.getItem("refreshToken"), info: 1 }
- axios.post('/api/auth/refresh', post, { ignoreErrors: true, loader: true })
+ axios.post('/api/auth/refresh', post, { ignoreErrors: true, loader: true, headers: { Authorization: null } })
.then(response => {
this.$root.loginUser(response.data, false)
})
diff --git a/src/routes/api.php b/src/routes/api.php
--- a/src/routes/api.php
+++ b/src/routes/api.php
@@ -16,6 +16,7 @@
],
static function () {
Route::post('login', [API\AuthController::class, 'login']);
+ Route::post('refresh', [API\AuthController::class, 'refresh']);
Route::post('password-policy-check', [API\V4\PolicyController::class, 'checkPassword']);
Route::post('password-reset/init', [API\PasswordResetController::class, 'init']);
@@ -39,7 +40,6 @@
Route::get('info', [API\AuthController::class, 'info']);
Route::get('location', [API\AuthController::class, 'location']);
Route::post('logout', [API\AuthController::class, 'logout']);
- Route::post('refresh', [API\AuthController::class, 'refresh']);
}
);
}
diff --git a/src/tests/Feature/Controller/AuthTest.php b/src/tests/Feature/Controller/AuthTest.php
--- a/src/tests/Feature/Controller/AuthTest.php
+++ b/src/tests/Feature/Controller/AuthTest.php
@@ -157,10 +157,7 @@
$response->assertStatus(200);
$this->assertTrue(!empty($json['access_token']));
- $this->assertTrue(
- ($this->expectedExpiry - 5) < $json['expires_in']
- && $json['expires_in'] < ($this->expectedExpiry + 5)
- );
+ $this->assertEqualsWithDelta($this->expectedExpiry, $json['expires_in'], 5);
$this->assertSame('bearer', $json['token_type']);
$this->assertSame($user->id, $json['id']);
$this->assertSame($user->email, $json['user']['email']);
@@ -181,10 +178,7 @@
$response->assertStatus(200);
$this->assertTrue(!empty($json['access_token']));
- $this->assertTrue(
- ($this->expectedExpiry - 5) < $json['expires_in']
- && $json['expires_in'] < ($this->expectedExpiry + 5)
- );
+ $this->assertEqualsWithDelta($this->expectedExpiry, $json['expires_in'], 5);
$this->assertSame('bearer', $json['token_type']);
// No user info in the response
@@ -298,13 +292,14 @@
*/
public function testRefresh(): void
{
- // Request with no token, testing that it requires auth
- $response = $this->post("api/auth/refresh");
- $response->assertStatus(401);
+ // Test refresh token requirement
+ $response = $this->post("api/auth/refresh", []);
+ $response->assertStatus(422);
- // Test the same using JSON mode
- $response = $this->json('POST', "api/auth/refresh", []);
- $response->assertStatus(401);
+ $json = $response->json();
+
+ $this->assertSame('error', $json['status']);
+ $this->assertSame(['refresh_token' => ['The refresh token field is required.']], $json['errors']);
// Login the user to get a valid token
$post = ['email' => 'john@kolab.org', 'password' => 'simple123'];
@@ -317,25 +312,25 @@
// Request with a valid token (include user info in the response)
$post = ['refresh_token' => $json['refresh_token'], 'info' => 1];
- $response = $this->actingAs($user)->post("api/auth/refresh", $post);
+ $response = $this->post("api/auth/refresh", $post);
$response->assertStatus(200);
$json = $response->json();
- $this->assertSame('john@kolab.org', $json['user']['email']);
+ $this->assertSame($user->email, $json['user']['email']);
$this->assertTrue(is_array($json['user']['statusInfo']));
$this->assertTrue(is_array($json['user']['settings']));
$this->assertTrue($json['access_token'] != $token);
- $this->assertTrue(
- ($this->expectedExpiry - 5) < $json['expires_in']
- && $json['expires_in'] < ($this->expectedExpiry + 5)
- );
+ $this->assertEqualsWithDelta($this->expectedExpiry, $json['expires_in'], 5);
$this->assertSame('bearer', $json['token_type']);
$new_token = $json['access_token'];
+ $new_refresh_token = $json['refresh_token'];
- // TODO: Shall we invalidate the old token?
+ // The old token should not work anymore
+ $response = $this->withHeaders(['Authorization' => 'Bearer ' . $token])->get("api/auth/info");
+ $response->assertStatus(401);
- // And if the new token is working
+ // Check if the new token is working
$response = $this->withHeaders(['Authorization' => 'Bearer ' . $new_token])->get("api/auth/info");
$response->assertStatus(200);
}

File Metadata

Mime Type
text/plain
Expires
Mon, Mar 30, 1:44 AM (3 d, 9 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18785082
Default Alt Text
D5730.1774835099.diff (8 KB)

Event Timeline