# GiaoAn24h auth.md

GiaoAn24h is a Vietnamese education-commerce platform (lesson plans, slides,
videos, audio, background music) at https://giaoan24h.com. This document is the
machine-readable authentication and registration reference for AI agents and
bots.

Discovery resources: `/.well-known/api-catalog` (RFC 9727 linkset),
`/.well-known/oauth-protected-resource` (RFC 9728 protected-resource
metadata), `/openapi.json` (OpenAPI 3.1), `/api-docs` (HTML documentation),
`/llms.txt` (agent guide), `/developers` (developer hub),
`/robots.txt` (crawl rules).

## Authorization-server metadata

GiaoAn24h does NOT operate an OAuth 2.0 / OIDC authorization server: there
is no issuer, no `/authorize` / `/token` endpoints, no JWKS, and therefore
no `/.well-known/oauth-authorization-server` document or client-credentials
registration. Google sign-in makes this site an OAuth *client* of Google —
Google is the authorization server, not GiaoAn24h.

What IS published is RFC 9728 **protected-resource** metadata at
`/.well-known/oauth-protected-resource`. It truthfully describes this
resource (the API origin), its documentation links, and `scopes_supported`
— scope names derived from the real access levels of the public API
(documented in `/openapi.json`):

| Scope | Real access level |
| --- | --- |
| `catalog:read` | Anonymous GETs: product detail, category listings, search, top-up denominations |
| `orders:read` / `orders:write` | Session-gated order listing/creation/polling (order polling also accepts the short-lived per-order access cookie) |
| `topup:read` / `topup:write` | Wallet top-up order polling / creation |
| `wallet:read` | Balance and ledger reads |
| `promos:validate` | Promo-code validation for checkout and top-up |
| `giftcodes:redeem` | Gift-code redemption into the wallet |
| `media:download` | Music quota/download and token-based file downloads |

Consequence: there are no client credentials, bearer tokens, or API keys for
machine-to-machine access. To act on behalf of a user, drive the same
session-based flows a browser uses. Sessions are HMAC-signed cookies
(`better-auth.session_data`), not bearer tokens. Agent overview:
`/llms.txt`; developer hub: `/developers`.

## Registration and sign-in endpoints

All endpoints below are real: the Better Auth SDK mounted at
`src/app/api/auth/[...all]/route.ts`, plus thin internal wrappers under
`/api/internal/auth/*`.

### Create an account

- `POST /api/auth/sign-up/email` — JSON body `{ "email", "password", "name"? }`.
  Creates the account and signs in immediately (autoSignIn).

### Sign in

- `POST /api/auth/sign-in/email` — password sign-in:
  `{ "email", "password" }`.
- `POST /api/auth/sign-in/email-otp` — email OTP (6-digit code, 10-minute
  expiry): first call `{ "email" }` sends the code; second call
  `{ "email", "otp" }` verifies it and signs in. UI wrappers:
  `POST /api/internal/auth/otp/send` and `POST /api/internal/auth/otp/verify`.
- `POST /api/auth/sign-in/magic-link` — magic link: `{ "email" }`; the
  emailed link (`GET /api/auth/sign-in/magic-link?token=…`) signs the user
  in when opened. UI wrapper: `POST /api/internal/auth/magic`.
- Google — social sign-in through the application UI / SDK
  (`authClient.signIn.social`, provider `google`); the flow redirects to
  Google and back to https://giaoan24h.com.

### Password recovery

- `POST /api/auth/forget-password` — `{ "email" }` sends a reset link.
- `POST /api/auth/reset-password` — `{ "token", "newPassword" }` completes
  the reset.

### Session

- `GET /api/auth/session` — current session JSON.
- `POST /api/auth/sign-out` — ends the session.

## Notes

- Email delivery (magic link / OTP / reset) is via Resend; without
  `RESEND_API_KEY` the sends are suppressed.
- Anti-bot and rate limiting apply to all endpoints (see `/robots.txt`).
- Public data (catalog, products, search) needs no authentication — see
  `/openapi.json` and `/api-docs`.
