superuser()->create();
$tokenOwner = User::factory()->create([
'username' => 'token-owner', 'first_name' => 'Token',
'last_name' => 'Owner',
'display_name' => 'Token Owner Display',
]);
$createdAt = now()->subHour();
$expiresAt = now()->addDay();
$personalClientId = DB::table('oauth_clients')->insertGetId([
'user_id' => null,
'name' => 'Personal Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 1,
'password_client' => 0,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
$nonPersonalClientId = DB::table('oauth_clients')->insertGetId([
'user_id' => null,
'name' => 'OAuth Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 0,
'password_client' => 1,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('oauth_access_tokens')->insert([
[
'id' => 'personal-token-1',
'user_id' => $tokenOwner->id,
'client_id' => $personalClientId,
'name' => 'Personal Token One',
'scopes' => '[]',
'revoked' => 0,
'created_at' => $createdAt,
'updated_at' => $createdAt,
'expires_at' => $expiresAt,
],
[
'id' => 'oauth-token-1',
'user_id' => $tokenOwner->id,
'client_id' => $nonPersonalClientId,
'name' => 'Non Personal Token',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
]);
$this->actingAs($superuser)
->get(route('settings.oauth.index'))
->assertOk()
->assertSee(trans('admin/settings/general.oauth_personal_access_tokens'))
->assertSee('Personal Token One')
->assertSee('Token Owner Display')
->assertSee(route('users.show', $tokenOwner))
->assertSee(Helper::getFormattedDateObject($createdAt, 'datetime', false))
->assertSee(Helper::getFormattedDateObject($expiresAt, 'datetime', false))
->assertDontSee('Non Personal Token');
}
public function test_personal_access_token_status_shows_active_revoked_or_expired(): void
{
$superuser = User::factory()->superuser()->create();
$personalClientId = DB::table('oauth_clients')->insertGetId([
'user_id' => null,
'name' => 'Personal Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 1,
'password_client' => 0,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('oauth_access_tokens')->insert([
[
'id' => 'status-active-token',
'user_id' => $superuser->id,
'client_id' => $personalClientId,
'name' => 'Active Status Token',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
[
'id' => 'status-revoked-token',
'user_id' => $superuser->id,
'client_id' => $personalClientId,
'name' => 'Revoked Status Token',
'scopes' => '[]',
'revoked' => 1,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
[
'id' => 'status-expired-token',
'user_id' => $superuser->id,
'client_id' => $personalClientId,
'name' => 'Expired Status Token',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now()->subDays(10),
'updated_at' => now()->subDays(10),
'expires_at' => now()->subDay(),
],
]);
$this->actingAs($superuser)
->get(route('settings.oauth.index'))
->assertOk()
->assertSee(trans('admin/settings/general.oauth_token_status_active'))
->assertSee(trans('admin/settings/general.oauth_token_status_revoked'))
->assertSee(trans('admin/settings/general.oauth_token_status_expired'));
}
public function test_permission_required_to_view_oauth_settings(): void
{
$this->actingAs(User::factory()->create())
->get(route('settings.oauth.index'))
->assertForbidden();
}
public function test_soft_deleted_token_owner_display_name_is_shown_with_strikethrough(): void
{
$superuser = User::factory()->superuser()->create();
$tokenOwner = User::factory()->create([
'username' => 'deleted-token-owner',
'display_name' => 'Deleted Token User',
]);
$tokenOwner->delete();
$personalClientId = DB::table('oauth_clients')->insertGetId([
'user_id' => null,
'name' => 'Personal Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 1,
'password_client' => 0,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('oauth_access_tokens')->insert([
'id' => 'soft-deleted-owner-token',
'user_id' => $tokenOwner->id,
'client_id' => $personalClientId,
'name' => 'Soft Deleted Owner Token',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
]);
$this->actingAs($superuser)
->get(route('settings.oauth.index'))
->assertOk()
->assertSee('Deleted Token User', false)
->assertSee(route('users.show', $tokenOwner));
}
public function test_authorized_applications_show_and_link_client_creator_with_soft_deleted_strikethrough(): void
{
$superuser = User::factory()->superuser()->create();
$activeCreator = User::factory()->create([
'display_name' => 'Active Client Creator',
'username' => 'active-creator',
]);
$softDeletedCreator = User::factory()->create([
'display_name' => 'Deleted Client Creator',
'username' => 'deleted-creator',
]);
$softDeletedCreator->delete();
$activeClientId = DB::table('oauth_clients')->insertGetId([
'user_id' => $activeCreator->id,
'name' => 'Authorized Client Active',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 0,
'password_client' => 0,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
$deletedClientId = DB::table('oauth_clients')->insertGetId([
'user_id' => $softDeletedCreator->id,
'name' => 'Authorized Client Deleted',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 0,
'password_client' => 0,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('oauth_access_tokens')->insert([
[
'id' => 'authorized-active-token',
'user_id' => $superuser->id,
'client_id' => $activeClientId,
'name' => 'Authorized Active Token',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
[
'id' => 'authorized-active-token-2',
'user_id' => $superuser->id,
'client_id' => $activeClientId,
'name' => 'Authorized Active Token Two',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
[
'id' => 'authorized-revoked-token',
'user_id' => $superuser->id,
'client_id' => $activeClientId,
'name' => 'Authorized Revoked Token',
'scopes' => '[]',
'revoked' => 1,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
[
'id' => 'authorized-deleted-token',
'user_id' => $superuser->id,
'client_id' => $deletedClientId,
'name' => 'Authorized Deleted Token',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
]);
$this->actingAs($superuser)
->get(route('settings.oauth.index'))
->assertOk()
->assertSee('Active Client Creator')
->assertSee(route('users.show', $activeCreator))
->assertSee('Deleted Client Creator', false)
->assertSee(route('users.show', $softDeletedCreator))
->assertDontSee('Authorized Active Token')
->assertDontSee('Authorized Active Token Two')
->assertDontSee('Authorized Deleted Token')
->assertDontSee('Authorized Revoked Token')
->assertSee('data-field="client_owner"', false)
->assertSee('data-sortable="true"', false);
}
public function test_oauth_clients_table_shows_associated_token_count_per_client_id(): void
{
$superuser = User::factory()->superuser()->create();
$ownedClientId = DB::table('oauth_clients')->insertGetId([
'user_id' => $superuser->id,
'name' => 'Owned OAuth Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 0,
'password_client' => 0,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
$otherClientId = DB::table('oauth_clients')->insertGetId([
'user_id' => User::factory()->create()->id,
'name' => 'Other OAuth Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 0,
'password_client' => 0,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('oauth_clients')->insert([
'user_id' => null,
'name' => 'Personal Access Legacy Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 1,
'password_client' => 0,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('oauth_clients')->insert([
'user_id' => null,
'name' => 'Password Grant Legacy Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 0,
'password_client' => 1,
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('oauth_clients')->insert([
'user_id' => null,
'name' => 'Revoked OAuth Legacy Client',
'secret' => 'secret',
'redirect' => 'http://localhost/callback',
'personal_access_client' => 0,
'password_client' => 0,
'revoked' => 1,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('oauth_access_tokens')->insert([
[
'id' => 'owned-client-token-1',
'user_id' => $superuser->id,
'client_id' => $ownedClientId,
'name' => 'Owned Client Token One',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
[
'id' => 'owned-client-token-2',
'user_id' => $superuser->id,
'client_id' => $ownedClientId,
'name' => 'Owned Client Token Two',
'scopes' => '[]',
'revoked' => 1,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
[
'id' => 'other-client-token-1',
'user_id' => $superuser->id,
'client_id' => $otherClientId,
'name' => 'Other Client Token One',
'scopes' => '[]',
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
'expires_at' => now()->addDay(),
],
]);
$this->actingAs($superuser)
->get(route('settings.oauth.index'))
->assertOk()
->assertSee(trans('admin/settings/general.oauth_associated_token_count'))
->assertSee(trans('admin/settings/general.oauth_client_type'))
->assertSee('Owned OAuth Client')
->assertSee('Personal Access Legacy Client')
->assertSee('Password Grant Legacy Client')
->assertSee('Revoked OAuth Legacy Client')
->assertSee(trans('admin/settings/general.oauth_client_type_oauth'))
->assertSee(trans('admin/settings/general.oauth_client_type_personal_access'))
->assertSee(trans('admin/settings/general.oauth_client_type_password_grant'))
->assertSee(trans('admin/settings/general.oauth_token_status_revoked'))
->assertSee('data-field="associated_token_count"', false)
->assertSee('data-field="client_type"', false)
->assertSeeInOrder(['Owned OAuth Client', '