> ## Documentation Index
> Fetch the complete documentation index at: https://system.muzemus.online/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> How staff members authenticate into MUZE using better-auth

## Authentication provider

MUZE uses **better-auth** for authentication. It is configured as an Express middleware handler mounted directly on the NestJS application at `/api/auth`. better-auth stores sessions and user records in the same PostgreSQL database via `@better-auth/prisma-adapter`.

## Key design decisions

| Decision                   | Rationale                                                                                                            |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **Session-based, not JWT** | Sessions are stored server-side in PostgreSQL. The browser holds an HTTP-only cookie. No token refresh logic needed. |
| **Self-sign-up disabled**  | `disableSignUp: true`: portal accounts are created by Muze Admin only via Account Management.                        |
| **No OAuth/SSO**           | Authentication is email + password only. No corporate identity provider integration.                                 |
| **Cross-site cookies**     | Production uses `SameSite=None; Secure` because frontend (Firebase) and backend (Render) are on different origins.   |

## Session cookie configuration

In production, better-auth sets these cookie attributes:

```
better-auth.session_token: <encrypted-token>
  HttpOnly: true
  SameSite: None
  Secure: true
  Path: /
```

In development, the default `SameSite: Lax` is used.

## Auth endpoints (better-auth built-in)

All auth endpoints live under `/api/auth` (outside the `/api/v1` prefix):

| Endpoint                    | Method | Purpose                                   |
| --------------------------- | ------ | ----------------------------------------- |
| `/api/auth/sign-in`         | POST   | Email + password sign-in                  |
| `/api/auth/sign-out`        | POST   | Destroy session                           |
| `/api/auth/forgot-password` | POST   | Send password reset email                 |
| `/api/auth/reset-password`  | POST   | Set new password via reset token          |
| `/api/auth/get-session`     | GET    | Return current session (used by frontend) |

## Session validation flow

Every authenticated request goes through `SessionGuard`:

```mermaid theme={null}
flowchart TD
    A[HTTP Request] --> B[Extract session token from cookie]
    B --> C[better-auth getSession from headers]
    C --> D{Session exists and not expired?}
    D -->|No| E[Throw 401 Unauthorized]
    D -->|Yes| F[Attach session to request.auth]
    F --> G[Continue to PermissionsGuard]
```

The `SessionGuard` calls `authService.getSession(request.headers)` which internally calls `better-auth`'s `getSession()` with the request headers. This queries the `Session` table in PostgreSQL to validate the token.

## Password management

* Passwords are hashed by better-auth using industry-standard algorithms (bcrypt by default)
* Password reset emails contain a token that links to `/reset-password?token=...`
* When a password is reset via the invite flow, the user's `emailVerified` flag is set to `true`
* There are no password complexity requirements enforced beyond what better-auth provides by default

## What MUZE does not support

* No multi-factor authentication (MFA)
* No OAuth / social login
* No SSO / SAML / OIDC
* No API key authentication
* No service-to-service authentication (all API calls are browser-initiated)
* No session rotation on privilege escalation
* No concurrent session limits
