# Iniciar sesión con UTILIA en Next.js

Añade el botón «Iniciar sesión con UTILIA» a una aplicación Next.js con Auth.js: UTILIA OS actúa como proveedor OpenID Connect y la configuración es mínima.

Con Auth.js (next-auth v5), UTILIA OS funciona como cualquier proveedor OpenID Connect: le das el emisor y las credenciales, y Auth.js descubre solo las direcciones de autorización, token y claves, hace PKCE y verifica el `id_token`. Esta guía usa Next.js con App Router.

## Antes de empezar

- Activa OAuth en tu aplicación externa, con el tipo **Con servidor propio (recomendado)**, como explica [Activar OAuth en tu aplicación](https://os.utilia.ai/docs/developers/oauth/apps-panel).
- Añade como dirección de vuelta `http://localhost:3000/api/auth/callback/utilia` para desarrollo y la de producción con tu dominio, por ejemplo `https://tu-app.com/api/auth/callback/utilia`.
- Ten a mano el identificador público y la clave secreta.

1. **Instala Auth.js**

   ```bash
   npm install next-auth@beta
   ```
2. **Configura el proveedor**

   Crea `auth.ts` en la raíz del proyecto:

   ```typescript
   import NextAuth from "next-auth"

   export const { handlers, auth, signIn, signOut } = NextAuth({
     providers: [
       {
         id: "utilia",
         name: "UTILIA",
         type: "oidc",
         issuer: "https://os.utilia.ai",
         clientId: process.env.AUTH_UTILIA_ID,
         clientSecret: process.env.AUTH_UTILIA_SECRET,
         checks: ["pkce", "state"],
       },
     ],
   })
   ```

   Con `type: "oidc"`, Auth.js lee `https://os.utilia.ai/.well-known/openid-configuration` y pide por defecto `openid profile email`. `checks` deja explícito el uso de PKCE, que UTILIA OS exige, y de `state`.
3. **Añade las variables de entorno**

   En `.env.local`:

   ```bash
   AUTH_UTILIA_ID=utilia_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   AUTH_UTILIA_SECRET=tu_clave_secreta
   AUTH_SECRET=genera_una_con_openssl_rand_base64_32
   ```

   `AUTH_SECRET` es la clave con la que Auth.js cifra sus sesiones; genérala con `openssl rand -base64 32`. La clave secreta de UTILIA OS va solo aquí, nunca en código que llegue al navegador.
4. **Crea la ruta de Auth.js**

   En `app/api/auth/[...nextauth]/route.ts`:

   ```typescript
   import { handlers } from "@/auth"

   export const { GET, POST } = handlers
   ```

   Si tu proyecto no tiene el alias `@/` apuntando a la raíz, importa `auth.ts` con una ruta relativa.
5. **Pon el botón**

   ```tsx
   "use client"

   import { signIn } from "next-auth/react"

   export function LoginButton() {
     return (
       <button type="button" onClick={() => signIn("utilia")}>
         Iniciar sesión con UTILIA
       </button>
     )
   }
   ```

   Para darle la imagen oficial, usa el estilo de [Botones y marca](https://os.utilia.ai/docs/developers/oauth/buttons-and-branding).

## Leer la sesión

En un componente de servidor:

```tsx
import { auth } from "@/auth"

export default async function Page() {
  const session = await auth()

  if (!session?.user) {
    return <p>No has iniciado sesión.</p>
  }

  return (
    <div>
      <p>Hola, {session.user.name}</p>
      <p>Correo: {session.user.email}</p>
    </div>
  )
}
```

En un componente de cliente, envuelve la aplicación con `SessionProvider` y usa `useSession`:

```tsx
// app/providers.tsx
"use client"

import { SessionProvider } from "next-auth/react"

export function Providers({ children }: { children: React.ReactNode }) {
  return <SessionProvider>{children}</SessionProvider>
}
```

```tsx
"use client"

import { useSession } from "next-auth/react"

export function UserInfo() {
  const { data: session, status } = useSession()

  if (status === "loading") return <p>Cargando...</p>
  if (!session) return <p>No has iniciado sesión.</p>

  return <p>Hola, {session.user?.name}</p>
}
```

`session.user` trae el nombre, el correo y la foto que llegan en el `id_token` (`name`, `email` y `picture`).

## Cerrar sesión

```tsx
"use client"

import { signOut } from "next-auth/react"

export function LogoutButton() {
  return (
    <button type="button" onClick={() => signOut()}>
      Cerrar sesión
    </button>
  )
}
```

`signOut()` cierra la sesión de tu aplicación. Si además guardas los tokens de UTILIA OS para llamar a sus servidores MCP, revócalos al cerrar sesión, como explica [Cierre de sesión desde tu aplicación](https://os.utilia.ai/docs/developers/oauth/logout).

## Si algo falla

- **La autorización vuelve con un error de redirección**: la dirección de vuelta del panel tiene que ser exactamente la de Auth.js, `.../api/auth/callback/utilia`.
- **`invalid_client` al canjear el código**: revisa `AUTH_UTILIA_ID` y `AUTH_UTILIA_SECRET`, y que la aplicación sea de tipo **Con servidor propio**.

Más casos en [Problemas frecuentes con OAuth](https://os.utilia.ai/docs/developers/oauth/troubleshooting).
