npm package: @mudah-starter/nuxtjs-auth
Description: Generic authentication module for Nuxt applications with Laravel Sanctum support
Author: iqbadev
Latest version: 1.0.1

# @mudah-starter/nuxtjs-auth

[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![License][license-src]][license-href]
[![Nuxt][nuxt-src]][nuxt-href]

A powerful authentication module for Nuxt 4+ applications with Laravel Sanctum support. This module provides seamless authentication integration with server-side rendering, client-side hydration, and an extensible event-driven architecture.

## ✨ Features

- 🚀 **SSR Compatible** - Works seamlessly with server-side rendering and client-side hydration
- 🔐 **Laravel Sanctum Integration** - Built specifically for Laravel Sanctum API authentication
- 🎣 **Event-Driven Hooks** - Extensible plugin system for auth lifecycle events
- 🍪 **Secure Token Storage** - Cookie-based storage with configurable security options
- 🔄 **Auto Token Management** - Automatic user data fetching and token validation
- 🛡️ **Route Protection** - Built-in middleware for protecting routes and pages
- 📱 **Universal Support** - Works on both server and client sides
- 🎨 **TypeScript First** - Full TypeScript support with proper type definitions
- ⚡ **Nuxt 4+ Ready** - Built for the latest Nuxt ecosystem

## 📦 Installation

```bash
npm install @mudah-starter/nuxtjs-auth
```

## 🚀 Quick Setup

Add the module to your `nuxt.config.ts`:

```typescript
export default defineNuxtConfig({
  modules: [
    '@mudah-starter/nuxtjs-auth'
  ],
  
  auth: {
    baseURL: 'https://your-api.com',
    endpoints: {
      login: '/api/v1/auth/login',
      logout: '/api/v1/auth/logout',
      user: '/api/v1/auth/me',
      refresh: '/api/v1/auth/refresh'
    }
  }
})
```

That's it! You can now use authentication in your Nuxt app ✨

## 📖 Basic Usage

### In Components/Pages

```vue
<template>
  <div>
    <!-- Loading state -->
    <div v-if="!auth.ready.value">
      Loading...
    </div>
    
    <!-- Authenticated user -->
    <div v-else-if="auth.loggedIn.value">
      <h1>Welcome, {{ auth.user.value?.name }}!</h1>
      <button @click="handleLogout">Logout</button>
    </div>
    
    <!-- Guest user -->
    <div v-else>
      <button @click="navigateTo('/auth/login')">Login</button>
    </div>
  </div>
</template>

<script setup>
const auth = useAuth()

const handleLogout = async () => {
  try {
    await auth.logout()
  } catch (error) {
    console.error('Logout failed:', error)
  }
}
</script>
```

### Login Form Example

```vue
<template>
  <form @submit.prevent="handleLogin">
    <div>
      <label>Email:</label>
      <input v-model="credentials.email" type="email" required />
    </div>
    <div>
      <label>Password:</label>
      <input v-model="credentials.password" type="password" required />
    </div>
    <button type="submit" :disabled="auth.loading.value">
      {{ auth.loading.value ? 'Logging in...' : 'Login' }}
    </button>
  </form>
</template>

<script setup>
const auth = useAuth()

const credentials = reactive({
  email: '',
  password: ''
})

const handleLogin = async () => {
  try {
    await auth.login(credentials)
    await navigateTo('/')
  } catch (error) {
    console.error('Login failed:', error.message)
  }
}
</script>
```

## ⚙️ Configuration

### Module Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `baseURL` | `string` | `'http://localhost:8000'` | API base URL for authentication |
| `serverBaseURL` | `string` | `undefined` | Internal server URL for SSR (optional) |
| `endpoints` | `object` | See below | Authentication API endpoints |
| `token` | `object` | See below | Token storage configuration |
| `redirect` | `object` | See below | Redirect paths configuration |
| `globalMiddleware` | `boolean` | `true` | Enable global authentication middleware |

### Complete Configuration Example

```typescript
export default defineNuxtConfig({
  modules: [
    '@mudah-starter/nuxtjs-auth'
  ],
  
  auth: {
    // Base URL for your Laravel API
    baseURL: 'https://your-api.com',
    
    // Optional: Server-side URL for SSR (if different from baseURL)
    serverBaseURL: 'http://localhost:8000',
    
    // API endpoints
    endpoints: {
      login: '/api/v1/auth/login',
      logout: '/api/v1/auth/logout',
      user: '/api/v1/auth/me',
      refresh: '/api/v1/auth/refresh'
    },
    
    // Token configuration
    token: {
      cookieName: 'auth-token',
      maxAge: 60 * 60 * 24 * 7, // 7 days
      secure: process.env.NODE_ENV === 'production',
      httpOnly: false,
      sameSite: 'lax'
    },
    
    // Redirect paths
    redirect: {
      login: '/auth/login',
      logout: '/auth/login',
      home: '/'
    },
    
    // Enable global middleware
    globalMiddleware: true
  }
})
```

### Token Configuration

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `cookieName` | `string` | `'auth-token'` | Cookie name for token storage |
| `maxAge` | `number` | `604800` | Cookie max age in seconds (7 days) |
| `secure` | `boolean` | `false` | HTTPS only cookies (set true in production) |
| `httpOnly` | `boolean` | `false` | HTTP only cookies |
| `sameSite` | `string` | `'lax'` | SameSite cookie attribute |

## 🎣 Event Hooks

Create powerful event handlers using plugins:

```typescript
// plugins/auth.client.ts
export default defineNuxtPlugin(() => {
  registerAuthEvents.onLogin(async (user, token) => {
    console.log('🎉 User logged in:', user.name)
    
    // Custom logic after login
    // Track analytics, initialize user preferences, etc.
  })

  registerAuthEvents.onLogout(async (user) => {
    console.log('👋 User logged out:', user?.name)
    
    // Custom cleanup logic
    // Clear local storage, reset app state, etc.
  })

  registerAuthEvents.onFetchUser(async (user) => {
    console.log('👤 User data fetched:', user.name)
    
    // Custom logic when user data is fetched
    // Load user preferences, set theme, etc.
  })

  registerAuthEvents.onRefreshUser(async (user) => {
    console.log('🔄 User data refreshed:', user.name)
    
    // Custom logic when user data is refreshed
  })
})
```

## 🛡️ Route Protection

The module automatically adds global middleware. Configure page-level authentication:

### Protected Pages
```vue
<script setup>
// Require authentication
definePageMeta({
  auth: true
})
</script>
```

### Guest Only Pages
```vue
<script setup>
// Allow only unauthenticated users
definePageMeta({
  auth: false
})
</script>
```

### Public Pages
```vue
<script setup>
// No auth requirement (default)
definePageMeta({
  auth: undefined
})
</script>
```

## 🔧 API Reference

### useAuth() Composable

The main composable providing authentication functionality:

#### Properties (Reactive)
- `user` - Current authenticated user or `null`
- `loading` - Loading state for auth operations
- `ready` - Initialization completion state
- `loggedIn` - Computed boolean indicating authentication status
- `isAuthenticated` - Alias for `loggedIn`

#### Methods

##### login(credentials)
Authenticate user with email and password:

```typescript
await auth.login({
  email: 'user@example.com',
  password: 'password123'
})
```

##### logout(redirect?)
Log out user with optional redirect:

```typescript
// Logout with redirect (default)
await auth.logout()

// Logout without redirect
await auth.logout(false)
```

##### fetchUser()
Fetch current user data from server:

```typescript
const user = await auth.fetchUser()
```

##### refresh()
Refresh authentication state:

```typescript
const success = await auth.refresh() // Returns boolean
```

### useAuthToken() Composable

Direct token management utilities:

```typescript
const { token, setToken, clearToken, hasToken } = useAuthToken()

// Check if token exists
if (hasToken()) {
  console.log('User has token')
}

// Get current token
const currentToken = token.value

// Manually set token
setToken('your-token-here')

// Clear token
clearToken()
```

## 🌐 Laravel Backend Requirements

Your Laravel API should return responses in this standardized format:

### Login Response
```json
{
  "success": true,
  "token": "your-sanctum-token-here",
  "message": "Login successful"
}
```

### User Response (/me endpoint)
```json
{
  "success": true,
  "data": {
    "id": 1,
    "name": "John Doe",
    "email": "john@example.com",
    "role": "user",
    "avatar": "https://example.com/avatar.jpg"
  }
}
```

### Error Response
```json
{
  "success": false,
  "message": "Invalid credentials",
  "errors": {
    "email": ["The email field is required."]
  }
}
```

## 🚨 Troubleshooting

### Common Issues

**CORS Errors**
- Ensure your Laravel API has proper CORS configuration
- Verify `withCredentials` settings in your API setup

**Token Not Persisting**
- Check cookie settings (`secure`, `sameSite`, `httpOnly`)
- Verify browser cookie storage in DevTools
- Ensure domain configuration is correct

**Hooks Not Executing**
- Ensure hooks are defined in client-side plugins (`.client.ts`)
- Check browser console for hook execution errors
- Verify event registration syntax

**TypeScript Errors**
- Ensure proper module import and setup
- Check that your User interface matches the expected format
- Verify Nuxt 4+ compatibility

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

### Development Setup

```bash
# Install dependencies
npm install

# Generate type stubs
npm run dev:prepare

# Develop with playground
npm run dev

# Build the module
npm run prepack

# Run tests
npm run test

# Lint code
npm run lint
```

## 📄 License

[MIT License](./LICENSE)

## 🙏 Credits

Built with ❤️ for the Nuxt community.

<!-- Badges -->
[npm-version-src]: https://img.shields.io/npm/v/@mudah-starter/nuxtjs-auth/latest.svg?style=flat&colorA=020420&colorB=00DC82
[npm-version-href]: https://npmjs.com/package/@mudah-starter/nuxtjs-auth

[npm-downloads-src]: https://img.shields.io/npm/dm/@mudah-starter/nuxtjs-auth.svg?style=flat&colorA=020420&colorB=00DC82
[npm-downloads-href]: https://npm.chart.dev/@mudah-starter/nuxtjs-auth

[license-src]: https://img.shields.io/npm/l/@mudah-starter/nuxtjs-auth.svg?style=flat&colorA=020420&colorB=00DC82
[license-href]: https://npmjs.com/package/@mudah-starter/nuxtjs-auth

[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js
[nuxt-href]: https://nuxt.com