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

# Authentication & Roles

> Better Auth (Google OAuth) and the six-tier RBAC model.

# Authentication & Roles

## Better Auth + Google OAuth

Authentication uses **Better Auth** with **Google OAuth** as the only sign-in
method. Sessions are stored in Neon (HttpOnly, Secure, SameSite=Lax cookies).
The auth routes are mounted at `/api/auth/[...all]`.

First sign-in routes a new user to `/onboarding` to collect phone, DOB, gender,
and consents; `POST /api/onboarding/complete` finalises the profile. UTM and
booking context survive the OAuth redirect via `sessionStorage`.

## RBAC — six roles

Roles are hierarchical: a higher role satisfies any lower-role requirement.

| Role           | Level | Typical access                                      |
| -------------- | ----- | --------------------------------------------------- |
| `customer`     | 0     | Own bookings, profile, gems, membership             |
| `staff`        | 1     | Own schedule + leave (`admin.theroyalglow.in/me/*`) |
| `receptionist` | 2     | Bookings, customers, leads, billing                 |
| `manager`      | 3     | + services, offers, staff, schedule, reports        |
| `owner`        | 4     | + users, branches                                   |
| `developer`    | 5     | + integrations, logs                                |

## Enforcing access in API routes

Two helpers guard server routes:

```ts theme={null}
import { requireSession, requireRole } from '@/lib/api/session'

// Any signed-in user
const session = await requireSession()

// Minimum role (throws 403 FORBIDDEN if below)
const session = await requireRole('receptionist')
```

* `requireSession()` throws `401 UNAUTHENTICATED` when there is no session.
* `requireRole(minRole)` throws `403 FORBIDDEN` when the user's role level is
  below the required minimum.

Each API page in the reference notes the minimum role for every endpoint.

## Route → role guidance

Customer endpoints live on `theroyalglow.in`; admin endpoints live on the
`admin.theroyalglow.in` subdomain at root paths (there is **no** `/api/admin/`
segment — the subdomain is the namespace).

| Route group                                                                                              | Minimum role   |
| -------------------------------------------------------------------------------------------------------- | -------------- |
| `theroyalglow.in/api/bookings`, `/api/membership`, `/api/gems`, `/api/notifications`                     | `customer`     |
| `admin.theroyalglow.in/api/me/*` (own schedule + leave)                                                  | `staff`        |
| `admin.theroyalglow.in/api/bookings`, `/api/customers`, `/api/leads`, `/api/billing`, `/api/memberships` | `receptionist` |
| `admin.theroyalglow.in/api/services`, `/api/offers`, `/api/staff`, `/api/schedule`, `/api/reports`       | `manager`      |
| `admin.theroyalglow.in/api/users`, `/api/branches`                                                       | `owner`        |
| `admin.theroyalglow.in/api/integrations`, `/api/logs`                                                    | `developer`    |

Public (no auth) customer endpoints: `GET theroyalglow.in/api/services`,
`GET /api/services/[slug]`, `GET /api/availability`, `POST /api/leads`,
`GET /api/health`.


## Related topics

- [API Reference](/content/docs/api-reference/index.md)
- [Security](/content/docs/security.md)
- [Pages & Routes](/content/docs/pages-and-routes.md)
- [Glossary](/content/docs/glossary.md)
- [Notifications & Email](/content/docs/notifications-email.md)
