# Authentication and delegation

**Authentication is not authorization.** This module establishes who is calling.
Every protected route separately decides what they may read.

## Browser sign-in (Google, Microsoft, GitHub)

Browser OAuth uses the authentication gateway. Set these values in `.env`:

```dotenv
AUTH_MODE=gateway
AUTH_GATEWAY_URL=https://oauth.xiangenhu.info
PUBLIC_BASE_URL=https://your-browser-facing-host
```

`PUBLIC_BASE_URL` must match the address you open in the browser; the gateway
returns to `/auth/callback` on that host. In Codespaces, use the forwarded port
URL for the current Codespace and make the port accessible to your browser.
Restart with `npm start` (after building) or `npm run dev` after changing `.env`.
`npm run dev:mock` explicitly overrides `AUTH_MODE` with `mock` and cannot be used
for gateway sign-in. Environment variables supplied by the shell also take
precedence over `.env`.

If `/auth/login?provider=google` returns `sign_in_unavailable`, the server is
running with a different authentication mode. `/api/v1/meta` reports the active
mode in `drivers.auth`; it must be `gateway` for browser OAuth.

## OIDC (production)

Bearer tokens validated for signature (via the issuer's JWKS), issuer, audience,
expiry, subject and scopes, with 30 seconds of clock tolerance.

| Claim | Use |
|---|---|
| `sub` | Required. Derives the internal owner identifier. |
| `iss`, `aud`, `exp` | Required and validated. |
| `roles` | `data_owner`, `researcher`, `application_client`, `system_administrator`. Defaults to `data_owner`. |
| `scope` / `scp` | Carried through for auditing. |
| `email` | If present and listed in `ADMIN_EMAILS`, adds the administrator role — which grants no content access. |
| `act.sub` / `on_behalf_of` | Delegation. Requires the `application_client` role. |

## Derived identifiers

```
ownerId  = "own_" + HMAC-SHA256(OWNER_KEY_SALT, "subject:" + sub)[:32]
ownerKey = "ok_"  + HMAC-SHA256(OWNER_KEY_SALT, "owner:" + ownerId)[:32]
```

The external subject never appears in an object key, an export or a log line.
`OWNER_KEY_SALT` is effectively permanent: changing it re-keys every derived
identifier and orphans existing data.

## Delegation

An application client acting for an owner receives that owner's `ownerId` and
`ownerKey` for the request, plus `delegatedOwnerId` and `applicationId`. It can
ingest and read, and the access decision records `actingAs: "delegate"`.

It cannot manage grants, request deletion or create exports. **Transmitting or
generating the data does not confer ownership of it.**

## Mock mode

Development and tests only; production configuration refuses it.

```
X-Mock-Subject: demo-owner
X-Mock-Roles: data_owner
X-Mock-Scopes: …
X-Mock-On-Behalf-Of: some-owner      # requires application_client
X-Mock-Application-Id: chat-app
```

Because `EventSource` cannot set headers, mock identity may also travel as
`?mockSubject=&mockRoles=` — accepted only when `AUTH_MODE=mock`.

## Cloud Tasks

Worker endpoints are not behind the user authenticator. They validate the Cloud
Tasks OIDC token against Google's JWKS, checking issuer, audience and the
calling service-account email. A shared secret (`WORKER_SHARED_SECRET`) is
accepted only outside production.
