authentikate/resources/views/livewire/manage-authentication-tokens.blade.php
Javier Feliz 2e95a2a271
Some checks failed
linter / quality (push) Successful in 5m47s
tests / ci (push) Failing after 10m17s
Move tokens to their own page
2025-08-02 15:54:30 -04:00

114 lines
6.2 KiB
PHP

<div class="max-w-4xl mx-auto py-12">
<x-card class="space-y-6 p-6">
<flux:heading size="lg">Authentication Tokens</flux:heading>
<flux:subheading>
Manage your active authentication tokens for different applications.
</flux:subheading>
@if($this->tokens->isEmpty())
<div class="text-center py-12">
<flux:icon.shield-check variant="outline" class="mx-auto h-12 w-12 text-zinc-400" />
<flux:heading size="md" class="mt-4">No tokens</flux:heading>
<flux:subheading class="mt-2">
You haven't authorized any applications yet.
</flux:subheading>
</div>
@else
<div class="space-y-6">
@foreach($this->tokens as $appName => $appTokens)
<div class="space-y-3" x-data="{ expanded: false }"
wire:key="app-{{ $appTokens->first()->application_id }}">
<div class="flex items-center space-x-3 cursor-pointer hover:bg-zinc-50 dark:hover:bg-zinc-800/50 p-2 rounded-lg transition-colors"
x-on:click="expanded = !expanded">
<div class="flex-shrink-0">
@if($appTokens->first()->application->icon)
<img class="h-8 w-8 rounded-lg object-cover"
src="{{ $appTokens->first()->application->getIconUrl() }}" alt="{{ $appName }}"
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
<div class="h-8 w-8 rounded-lg bg-zinc-100 dark:bg-zinc-700 flex items-center justify-center"
style="display: none;">
<flux:icon.computer-desktop class="h-5 w-5 text-zinc-500" />
</div>
@else
<div class="h-8 w-8 rounded-lg bg-zinc-100 dark:bg-zinc-700 flex items-center justify-center">
<flux:icon.computer-desktop class="h-5 w-5 text-zinc-500" />
</div>
@endif
</div>
<div class="flex-1">
<flux:heading size="sm">{{ $appName }}</flux:heading>
<flux:subheading size="xs">{{ $appTokens->count() }} {{ $appTokens->count() === 1 ? 'token' :
'tokens' }}</flux:subheading>
</div>
<div class="flex-shrink-0">
<flux:icon.chevron-down class="h-5 w-5 text-zinc-400 transition-transform duration-200"
x-bind:class="expanded ? 'rotate-180' : ''" />
</div>
</div>
<div class="ml-11 space-y-2" x-show="expanded" x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 transform -translate-y-2"
x-transition:enter-end="opacity-100 transform translate-y-0"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 transform translate-y-0"
x-transition:leave-end="opacity-0 transform -translate-y-2">
@foreach($appTokens as $token)
<x-card class="p-4" wire:key="token-{{ $token->id }}">
<div class="flex items-center justify-between">
<div class="flex-1 min-w-0">
<div class="space-y-1">
<flux:subheading size="xs">
<flux:icon.calendar class="inline h-3 w-3 mr-1" />
Issued: {{ $token->issued_at->format('M j, Y \a\t g:i A') }}
</flux:subheading>
@if($token->expires_at)
<flux:subheading size="xs">
<flux:icon.clock class="inline h-3 w-3 mr-1" />
Expires: {{ $token->expires_at->format('M j, Y \a\t g:i A') }}
</flux:subheading>
@endif
@if($token->ip)
<flux:subheading size="xs">
<flux:icon.globe-alt class="inline h-3 w-3 mr-1" />
IP: {{ $token->ip }}
</flux:subheading>
@endif
@if($token->user_agent)
<flux:subheading size="xs" class="truncate">
<flux:icon.device-phone-mobile class="inline h-3 w-3 mr-1" />
<span title="{{ $token->user_agent }}">
{{ strlen($token->user_agent) > 60 ? substr($token->user_agent, 0, 60) .
'...' :
$token->user_agent }}
</span>
</flux:subheading>
@endif
</div>
</div>
<div class="flex-shrink-0 ml-4">
<flux:button wire:click="revokeToken({{ $token->id }})" icon="trash"
wire:confirm="Are you sure you want to revoke this token? The application will need to be re-authorized."
variant="danger" size="sm">
Revoke
</flux:button>
</div>
</div>
</x-card>
@endforeach
</div>
</div>
@endforeach
</div>
@endif
</x-card>
@script
<script>
$wire.on('token-revoked', () => {
// You can add a toast notification here if you have one
console.log('Token revoked successfully');
});
</script>
@endscript
</div>