Cookbook & Integration Examples

Realistic recipes for Laravel Sanctum, custom REST APIs, SSR Dashboards, and Session Managers.

Reference & Recipes Nuxt 3.12+ / Nuxt 4 / TypeScript

Laravel Sanctum / API Integration

Laravel APIs often issue plaintext API tokens via Sanctum:

Laravel Controller

php
// app/Http/Controllers/AuthController.php
public function login(Request $request)
{
    $credentials = $request->validate([
        'email' => 'required|email',
        'password' => 'required',
    ]);

    if (!Auth::attempt($credentials)) {
        return response()->json(['message' => 'Invalid credentials'], 401);
    }

    $user = Auth::user();
    $token = $user->createToken('nuxt-session')->plainTextToken;

    return response()->json([
        'success' => true,
        'message' => 'Authenticated successfully',
        'data' => [
            'token' => $token,
            'user' => $user,
        ]
    ]);
}

Nuxt Configuration

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-bearer-auth'],
  bearerAuth: {
    apiBaseUrl: 'https://laravel-api.example.com/api',
    redisUrl: process.env.REDIS_URL,
    endpoints: {
      login: 'login',
      logout: 'logout',
      me: 'user',
    },
  },
})

Generic Node/Go/Python Bearer API

For a FastAPI or Express backend issuing JWT bearer tokens:

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['nuxt-bearer-auth'],
  bearerAuth: {
    apiBaseUrl: 'https://api.myapp.com',
    endpoints: {
      login: 'auth/token',
      refresh: 'auth/refresh',
      me: 'auth/profile',
    },
    responsePaths: {
      token: ['access_token'],
      refreshToken: ['refresh_token'],
      user: ['user_info'],
    }
  }
})

SSR Authenticated Dashboard Recipe

Here is a full-page SSR Dashboard that fetches data securely during server rendering:

vue
<script setup lang="ts">
// Page requires authentication (protected by default middleware)
const auth = useBearerAuth()

// Fetch dashboard data during SSR using the Nuxt server route
const { data: analytics, pending, error } = await useFetch('/api/dashboard/stats')

async function handleLogout() {
  await auth.logout()
}
</script>

<template>
  <div class="dashboard-layout">
    <header class="flex justify-between items-center p-4 border-b">
      <div>
        <h2 class="text-xl font-bold">Welcome back, {{ auth.user.value?.name }}</h2>
        <p class="text-sm text-gray-500">{{ auth.user.value?.email }}</p>
      </div>
      <button @click="handleLogout" class="px-4 py-2 bg-red-600 text-white rounded">
        Log Out
      </button>
    </header>

    <main class="p-6">
      <div v-if="pending">Loading dashboard metrics...</div>
      <div v-else-if="error">Error loading metrics: {{ error.message }}</div>
      <div v-else class="grid grid-cols-3 gap-6">
        <div class="metric-card">
          <span class="label">Total Orders</span>
          <span class="val">{{ analytics?.totalOrders }}</span>
        </div>
        <div class="metric-card">
          <span class="label">Revenue</span>
          <span class="val">${{ analytics?.revenue }}</span>
        </div>
        <div class="metric-card">
          <span class="label">Active Sessions</span>
          <span class="val">{{ analytics?.activeSessions }}</span>
        </div>
      </div>
    </main>
  </div>
</template>

Multi-Device Session Manager UI

Allow your users to view all currently active browser sessions and remotely revoke unrecognized devices:

vue
<script setup lang="ts">
import type { PublicSession } from 'nuxt-bearer-auth'

// GET /api/auth/sessions returns { sessions: PublicSession[] }
const { data, refresh, pending } = await useFetch<{ sessions: PublicSession[] }>('/api/auth/sessions')
const revokingId = ref<string | null>(null)

async function revoke(id: string) {
  revokingId.value = id
  try {
    await $fetch(`/api/auth/sessions/${id}`, { method: 'DELETE' })
    await refresh()
  } finally {
    revokingId.value = null
  }
}
</script>

<template>
  <div class="max-w-3xl mx-auto p-6">
    <h2 class="text-2xl font-bold mb-4">Security & Active Devices</h2>
    <p class="text-gray-400 mb-6">Manage active sessions logged into your account across devices.</p>

    <div v-if="pending" class="text-gray-400">Loading active sessions...</div>

    <div v-else class="space-y-4">
      <div
        v-for="s in data?.sessions"
        :key="s.id"
        class="p-4 rounded-xl border border-gray-800 bg-gray-900/60 flex items-center justify-between"
      >
        <div class="space-y-1">
          <div class="flex items-center gap-2">
            <span class="font-medium text-white">{{ s.userAgent || 'Unknown Device' }}</span>
            <span class="text-xs px-2 py-0.5 rounded bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
              Active
            </span>
          </div>
          <p class="text-xs text-gray-400">
            IP: {{ s.ipAddress || 'Unknown' }} · Last active: {{ new Date(s.lastActivity).toLocaleString() }}
          </p>
        </div>

        <button
          @click="revoke(s.id)"
          :disabled="revokingId === s.id"
          class="px-3 py-1.5 text-xs font-medium text-red-400 hover:text-red-300 hover:bg-red-500/10 rounded-lg border border-red-500/20 transition"
        >
          {{ revokingId === s.id ? 'Revoking...' : 'Revoke Session' }}
        </button>
      </div>
    </div>
  </div>
</template>