Integrate the Char agent into your Laravel application with Livewire. The key is placing the agent outside your Livewire components so it persists across updates.
Installation
Basic Usage
Place the agent in your layout, outside Livewire components:
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html>
<head>
<meta name="id-token" content="{{ auth()->user()?->id_token }}">
@vite(['resources/css/app.css', 'resources/js/app.js'])
@livewireStyles
</head>
<body>
<div>
{{ $slot }}
</div>
{{-- Agent outside Livewire components persists --}}
<char-agent id="chat-widget"></char-agent>
@livewireScripts
<script type="module">
import '@mcp-b/char/web-component';
document.addEventListener('livewire:navigated', () => {
const agent = document.getElementById('chat-widget');
const idToken = document.querySelector('meta[name="id-token"]')?.content;
const clientId = document.querySelector('meta[name="client-id"]')?.content;
if (agent && idToken && clientId) {
agent.connect({ idToken, clientId });
}
});
// Also connect on initial load
document.addEventListener('DOMContentLoaded', () => {
const agent = document.getElementById('chat-widget');
const idToken = document.querySelector('meta[name="id-token"]')?.content;
const clientId = document.querySelector('meta[name="client-id"]')?.content;
if (agent && idToken && clientId) {
agent.connect({ idToken, clientId });
}
});
</script>
</body>
</html>
With Laravel Socialite
If using Socialite for OAuth:
// app/Http/Controllers/Auth/OAuthController.php
class OAuthController extends Controller
{
public function callback(string $provider)
{
$socialiteUser = Socialite::driver($provider)->user();
// Store the ID token in session or user model
session(['id_token' => $socialiteUser->token]);
// Or store on user
$user = User::updateOrCreate(
['email' => $socialiteUser->email],
['id_token' => $socialiteUser->token]
);
auth()->login($user);
return redirect('/dashboard');
}
}
Alpine.js Integration
If using Alpine.js alongside Livewire:
<char-agent
id="chat-widget"
x-data
x-init="$el.connect({ idToken: '{{ auth()->user()?->id_token }}', clientId: '{{ config('services.char.client_id') }}' })"
></char-agent>
With Livewire Component
Create a Livewire component for dynamic token updates:
// app/Livewire/CharAgent.php
<?php
namespace App\Livewire;
use Livewire\Component;
class CharAgent extends Component
{
public ?string $idToken = null;
public function mount()
{
$this->idToken = auth()->user()?->id_token;
}
public function render()
{
return view('livewire.char-agent');
}
}
{{-- resources/views/livewire/char-agent.blade.php --}}
<div wire:ignore>
@if($idToken)
<char-agent
id="chat-widget"
x-data
x-init="$el.connect({ idToken: '{{ $idToken }}', clientId: '{{ config('services.char.client_id') }}' })"
></char-agent>
@endif
</div>
Use wire:ignore to prevent Livewire from updating the agent element, which would disconnect it.
SSR with Ticket Exchange
For enhanced security, exchange tokens server-side:
// app/Services/CharService.php
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class CharService
{
public function getTicket(string $idToken): ?array
{
$response = Http::withToken($idToken)
->post('https://api.usechar.ai/api/auth/ticket', [
'client_id' => config('services.char.client_id'),
]);
if ($response->successful()) {
return $response->json();
}
return null;
}
}
@php
$ticketAuth = app(App\Services\CharService::class)->getTicket(auth()->user()->id_token);
@endphp
@if($ticketAuth)
<char-agent
id="chat-widget"
x-data
x-init="$el.connect({ ticketAuth: {{ json_encode($ticketAuth) }} })"
></char-agent>
@endif
See Also