npm package: @fcfmclub/auth
Description: Paquete de autenticación OAuth propietario para aplicaciones FCFM Club
Author: FCFM Club
Latest version: 1.1.13

# @fcfmclub/auth

Sistema de autenticación OAuth propietario para aplicaciones FCFM Club. Similar a NextAuth pero específicamente diseñado para la API de FCFM Club.

## Instalación

```bash
npm install @fcfmclub/auth
```

## Configuración

### 1. Variables de entorno

Crea un archivo `.env.local` en tu proyecto Next.js:

```env
# Requeridas
OAUTH_CLIENT_ID="tu-client-id"
OAUTH_CLIENT_SECRET="tu-client-secret"

# Opcional (para el cliente)
NEXT_PUBLIC_OAUTH_CLIENT_ID="tu-client-id"
NEXT_PUBLIC_API_URL="https://alpha.fcfm.club/api"
```

### 2. Configurar ruta catch-all

Crea el archivo `app/auth/[...fcfmauth]/route.ts`:

**Opción 1: Configuración simple (recomendada)**

```typescript
export { GET, POST } from "@fcfmclub/auth";
```

**Opción 2: Configuración personalizada**

```typescript
import { createFCFMAuth } from "@fcfmclub/auth";
import { NextRequest } from "next/server";

const fcfmAuth = createFCFMAuth({
  apiUrl: process.env.NEXT_PUBLIC_API_URL || "https://alpha.fcfm.club/api",
  successRedirect: "/dashboard", // Opcional
  errorRedirect: "/auth/error", // Opcional
  // clientId y clientSecret se toman automáticamente de las variables de entorno
});

export async function GET(
  request: NextRequest,
  { params }: { params: { fcfmauth: string[] } },
) {
  return fcfmAuth.handleAuth(request, params);
}

export async function POST(
  request: NextRequest,
  { params }: { params: { fcfmauth: string[] } },
) {
  return fcfmAuth.handleAuth(request, params);
}
```

### 3. Agregar AuthProvider

Envuelve tu aplicación con el `AuthProvider` en `app/layout.tsx`:

```typescript
import { AuthProvider } from "@fcfmclub/auth";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="es">
      <body>
        <AuthProvider
          config={{
            apiUrl: process.env.NEXT_PUBLIC_API_URL || "https://alpha.fcfm.club/api",
            clientId: process.env.NEXT_PUBLIC_OAUTH_CLIENT_ID,
          }}
        >
          {children}
        </AuthProvider>
      </body>
    </html>
  );
}
```

### 4. (Opcional) Página de error

Crea `app/auth/error/page.tsx`:

```typescript
"use client";

import { useSearchParams } from "next/navigation";

export default function AuthErrorPage() {
  const searchParams = useSearchParams();
  const message = searchParams.get("message") || "Error de autenticación";

  return (
    <div className="flex items-center justify-center min-h-screen">
      <div className="text-center">
        <h1 className="text-2xl font-bold mb-4">Error de Autenticación</h1>
        <p className="text-gray-600 mb-6">{message}</p>
        <a href="/" className="text-blue-600 hover:underline">
          Volver al inicio
        </a>
      </div>
    </div>
  );
}
```

## Uso

### Hook useAuth

```typescript
"use client";

import { useAuth } from "@fcfmclub/auth";

export default function ProfilePage() {
  const { user, loading, isAuthenticated, loginWithGoogle, logout } = useAuth();

  if (loading) {
    return <div>Cargando...</div>;
  }

  if (!isAuthenticated) {
    return (
      <div>
        <h1>No estás autenticado</h1>
        <button onClick={loginWithGoogle}>
          Iniciar sesión con Google
        </button>
      </div>
    );
  }

  return (
    <div>
      <h1>Bienvenido, {user?.name}</h1>
      <p>Email: {user?.email}</p>
      <p>Batería: {user?.battery.percentage}%</p>
      <button onClick={logout}>Cerrar sesión</button>
    </div>
  );
}
```

### Rutas disponibles

El paquete maneja automáticamente las siguientes rutas:

- `/auth/signin` - Inicia el flujo de autenticación OAuth
- `/auth/callback` - Callback de OAuth (intercambia código por token)
- `/auth/logout` - Cierra la sesión

### Verificar autenticación del lado del servidor

```typescript
import { cookies } from "next/headers";

export default async function ServerPage() {
  const cookieStore = await cookies();
  const authToken = cookieStore.get("auth_token");
  const userInfo = cookieStore.get("user_info");

  if (!authToken) {
    return <div>No autenticado</div>;
  }

  const user = JSON.parse(userInfo?.value || "{}");

  return <div>Hola, {user.name}</div>;
}
```

## API

### FCFMAuthConfig

```typescript
interface FCFMAuthConfig {
  /** URL base de la API */
  apiUrl?: string;
  /** Client ID (default: process.env.OAUTH_CLIENT_ID) */
  clientId?: string;
  /** Client Secret (default: process.env.OAUTH_CLIENT_SECRET) */
  clientSecret?: string;
  /** Ruta de redirección después del login (default: "/") */
  successRedirect?: string;
  /** Ruta de página de error (default: "/auth/error") */
  errorRedirect?: string;
  /** Ambiente (default: process.env.NODE_ENV) */
  environment?: "production" | "development";
}
```

### AuthContextType

```typescript
interface AuthContextType {
  user: UserWithBattery | null;
  loading: boolean;
  login: (email: string, password: string) => Promise<void>;
  loginWithGoogle: () => void;
  logout: () => Promise<void>;
  refreshUser: () => void;
  isAuthenticated: boolean;
}
```

## Cookies

El paquete utiliza las siguientes cookies:

- `auth_token` - Token de acceso (no HTTP-only para permitir uso en cliente)
- `refresh_token` - Token de refresco (HTTP-only, seguro)
- `user_info` - Información del usuario (no HTTP-only)

## Seguridad

- En producción, todas las cookies se marcan como `secure` (solo HTTPS)
- El `client_secret` nunca se expone al cliente
- El intercambio de código por token se hace del lado del servidor
- Los tokens tienen expiración automática

## Licencia

MIT

## Autor

FCFM Club