# gizweb:auth/main

Auth: who is asking, for every gizweb app. It owns the people, their sessions, teams and roles, proofs of a mailbox, API tokens and (with the passkey and OAuth modules) the other ways in. An app asks `current` for the person of a request, and the Gate judges with their team grants (Gate.grantOf): pages, tools, agents and APIs share that one rule. The rows are the app's own: every function takes the Data.Db of the thread that serves the request (see records.giz).

```gizlang
import * as Main from "gizweb:auth/main";
```

## Types

### `Site`

```gizlang
type Site<C> = { prefix: string; home: string; origin: string; title: string; password: bool; secret: bytes; db: (context: C) => Data.Db; sys: (context: C) => System; shell: (context: C) => App.Shell; mail: (context: C, to: string, link: string) => bool; }
```

What the sign-in routes need of an app. PREFIX is where they are served ("/auth"), HOME where a signed-in person goes, ORIGIN
the app's own address (a mailed link starts with it, never with the request's Host, which a client chooses). PASSWORD turns on
the password field; without it a person signs in by a mailed link only. MAIL sends LINK to the address TO and says whether it
was sent. The other functions read the app's context: its records (this thread's Data.Db), its System and its page shell.

Opaque: create and use it through this module's functions.

## Functions

### `principalOf`

```gizlang
function principalOf(p: Person): Security.Principal
```

The principal of a person, for the Gate.

### `install`

```gizlang
function install(db: Data.Db): bool throws Model.Rejection
```

The tables of this module, made when missing. Their changes are additive: an existing table keeps its rows. Call it once on
the app's records before it serves.

Effects: fail, read, write, console, io.

### `signUp`

```gizlang
function signUp(sys: System, db: Data.Db, email: string, name: string, password: string, now: i64): Person throws Model.Rejection
```

A new account of EMAIL named NAME. A password is optional: "" makes an account for a passkey or a link.

Effects: fail, read, write, console, io.

### `insertPerson`

```gizlang
function insertPerson(db: Data.Db, person: Person): Person throws Model.Rejection
```

Adds PERSON with the id it has (an importer's account: its principal id, its bcrypt hash, its verified time). The
address is kept lowercase, and an address that is taken is refused.

Effects: fail, read, write, console, io.

### `signIn`

```gizlang
function signIn(sys: System, db: Data.Db, email: string, password: string): Person throws Model.Rejection
```

The person of EMAIL with PASSWORD. Its failure is SIGN_IN_FAILED, whichever part was wrong. A bcrypt password that an
import brought is stored again as this module stores passwords, at its first use.

Effects: fail, read, write, console, io.

### `startSession`

```gizlang
function startSession(sys: System, db: Data.Db, person: Person, label: string, now: i64): string throws Model.Rejection
```

A new session of PERSON on the device LABEL: the token for its cookie.

Effects: fail, read, write, console, io.

### `current`

```gizlang
function current(db: Data.Db, secret: bytes, request: Http.Request, now: i64): Result<Option<Person>, Model.Rejection>
```

The person a request is signed in as at NOW, or undefined. A session row, an API token, or gizstack's older signed
token (valid until 30 days after it was issued and not after a sign-out everywhere).

Effects: fail, read, write, console, io.

### `personOf`

```gizlang
function personOf(db: Data.Db, secret: bytes, token: string, now: i64): Result<Option<Person>, Model.Rejection>
```

The person of TOKEN at NOW (as `current` reads it from a request), or undefined.

Effects: fail, read, write, console, io.

### `personById`

```gizlang
function personById(db: Data.Db, id: string): Result<Option<Person>, Model.Rejection>
```

The person with the id ID, or undefined.

Effects: fail, read, write, console, io.

### `signOut`

```gizlang
function signOut(db: Data.Db, token: string, now: i64): bool throws Model.Rejection
```

Signs out one session by its token: this device only.

Effects: fail, read, write, console, io.

### `signOutEverywhere`

```gizlang
function signOutEverywhere(db: Data.Db, person: string, now: i64): bool throws Model.Rejection
```

Signs PERSON out of every device, and of every older token.

Effects: fail, read, write, console, io.

### `linkFor`

```gizlang
function linkFor(sys: System, db: Data.Db, email: string, purpose: string, now: i64): Result<Option<string>, Model.Rejection>
```

The raw token of a new proof of PURPOSE ("verify", "reset" or "login") for EMAIL, when an account has it. The caller
mails the link whatever the answer, so an address is never revealed by the reply.

Effects: fail, read, write, console, io.

### `signInWithLink`

```gizlang
function signInWithLink(db: Data.Db, raw: string, now: i64): Person throws Model.Rejection
```

The person of a magic link (purpose "login"), who is then proven to own the address.

Effects: fail, read, write, console, io.

### `verifyMailbox`

```gizlang
function verifyMailbox(db: Data.Db, raw: string, now: i64): bool throws Model.Rejection
```

Proves the mailbox of the verify link RAW.

Effects: fail, read, write, console, io.

### `linkOpen`

```gizlang
function linkOpen(db: Data.Db, raw: string, purpose: string, now: i64): bool throws Model.Rejection
```

Whether RAW is a live link of PURPOSE at NOW, without using it: what a page checks before it shows the form the link opens.

Effects: fail, read, write, console, io.

### `resetPassword`

```gizlang
function resetPassword(sys: System, db: Data.Db, raw: string, password: string, now: i64): Person throws Model.Rejection
```

Sets the password of the reset link RAW to PASSWORD and gives the person, to sign in. Every session of the person ends with
it. A dead link is refused before the password is hashed, which is slow on purpose.

Effects: fail, read, write, console, io.

### `newApiToken`

```gizlang
function newApiToken(sys: System, db: Data.Db, person: string, name: string, expires: i64, now: i64): string throws Model.Rejection
```

A new API token of PERSON named NAME, ending at EXPIRES (ms, 0 never). Returned once; only its digest is stored.

Effects: fail, read, write, console, io.

### `revokeApiToken`

```gizlang
function revokeApiToken(db: Data.Db, person: string, digest: string, now: i64): bool throws Model.Rejection
```

Ends one of PERSON's API tokens at NOW. DIGEST is the token's digest as `tokensOf` lists it, so a page never holds a secret.

Effects: fail, read, write, console, io.

### `devicesOf`

```gizlang
function devicesOf(db: Data.Db, person: string, now: i64): Vec<Session> throws Model.Rejection
```

The sessions of PERSON open at NOW, for a devices list.

Effects: fail, read, write, console, io.

### `revokeDevice`

```gizlang
function revokeDevice(db: Data.Db, person: string, digest: string, now: i64): bool throws Model.Rejection
```

Ends one of PERSON's sessions by its digest (a devices list's row), at NOW.

Effects: fail, read, write, console, io.

### `tokensOf`

```gizlang
function tokensOf(db: Data.Db, person: string): Vec<ApiToken> throws Model.Rejection
```

PERSON's API tokens, newest first.

Effects: fail, read, write, console, io.

### `addPasskey`

```gizlang
function addPasskey(secret: bytes, db: Data.Db, person: string, name: string, rpId: string, origin: string, challengeText: string, json: bytes, attestation: bytes, now: i64): bool throws Model.Rejection
```

Keeps the passkey that the registration ceremony ATTESTATION answers (see Passkeys.register) for PERSON, named NAME.

Effects: fail, read, write, console, io.

### `signInWithPasskey`

```gizlang
function signInWithPasskey(secret: bytes, db: Data.Db, rpId: string, origin: string, challengeText: string, id: string, json: bytes, data: bytes, signature: bytes, now: i64): Person throws Model.Rejection
```

The person who signs in with the passkey ID, once its assertion (DATA, SIGNATURE, over the client data JSON) answers the
challenge. The counter it reports is kept, so a copy of the credential is refused.

Effects: fail, read, write, console, io.

### `signInWithIdentity`

```gizlang
function signInWithIdentity(sys: System, db: Data.Db, id: Identity, now: i64): Person throws Model.Rejection
```

The person of a sign-in with a provider's IDENTITY, at NOW. A linked subject is its person. Otherwise the verified
address decides: a verified account of it is linked and signed in; an unverified one is taken over, as the mailbox owner
(its password and its sessions end); a new address makes an account. The link is kept for the next sign-in.

Effects: fail, read, write, console, io.

### `ssoProvider`

```gizlang
function ssoProvider(connection: string): string
```

The provider of an enterprise SSO connection: each connection is a provider of its own, `sso:${connection}`.

Effects: fail.

### `linkSso`

```gizlang
function linkSso(db: Data.Db, connection: string, subject: string, person: string, email: string, active: bool, profile: string, now: i64): bool throws Model.Rejection
```

Records what the directory of CONNECTION says about SUBJECT: its PERSON, whether it may sign in (ACTIVE) and its PROFILE
(JSON text, "" when none). A sync calls it for each user it reads; the row is updated when it exists. A link that is not
active refuses sign-in, so a user the directory removed cannot sign in with it.

Effects: fail, read, write, console, io.

### `linksOf`

```gizlang
function linksOf(db: Data.Db, person: string): Vec<ProviderLink> throws Model.Rejection
```

The provider links of PERSON, in the order they were made.

Effects: fail, read, write, console, io.

### `carriedRow`

```gizlang
function carriedRow(refreshToken: string, person: string, now: i64, expires: i64): ImportedSession
```

The row that carries a refresh session of the earlier system to this app: its cookie is kept as its digest, its person is
PERSON, the row was made at NOW and the cookie expires at EXPIRES. The importer stores the row, never the cookie.

Effects: fail.

### `importCarried`

```gizlang
function importCarried(db: Data.Db, refreshToken: string, person: string, now: i64, expires: i64): bool throws Model.Rejection
```

Records a carried refresh session of PERSON, from its cookie REFRESHTOKEN, made at NOW and good until EXPIRES.

Effects: fail, read, write, console, io.

### `adoptRefresh`

```gizlang
function adoptRefresh(sys: System, db: Data.Db, refreshToken: string, now: i64): Result<Option<Sessions.Carried>, Model.Rejection>
```

The session of a `refreshToken` cookie at NOW, once (see Sessions.adoptRefresh). The caller sets the new session cookie and
clears `refreshToken` when this gives a session.

Effects: fail, read, write, console, io.

### `oidcToken`

```gizlang
function oidcToken(sys: System, db: Data.Db, issuer: Oidc.OidcIssuer, req: Oidc.OidcToken, now: i64): string throws Model.Rejection
```

The token response of a token request (see Oidc.grant): the ID token, an access token (an API token of the person, for
ACCESS_LIFE) and the refresh token that replaces the one used.

Effects: fail, read, write, console, io.

### `oidcUserinfo`

```gizlang
function oidcUserinfo(db: Data.Db, token: string, now: i64): Result<Option<string>, Model.Rejection>
```

The userinfo claims of an access token from `oidcToken`, at NOW; undefined when it is not a live one.

Effects: fail, read, write, console, io.

### `importTotp`

```gizlang
function importTotp(db: Data.Db, person: string, secret: string, backup: string, on: bool, now: i64): bool throws Model.Rejection
```

Keeps PERSON's two-factor sign-in as it was at the move (see Totp.importFor).

Effects: fail, read, write, console, io.

### `importPasskey`

```gizlang
function importPasskey(db: Data.Db, person: string, name: string, credential: Passkeys.Credential, now: i64): bool throws Model.Rejection
```

Keeps a passkey of PERSON as it was at the move (see Passkey.add).

Effects: fail, read, write, console, io.

### `person`

```gizlang
function person<C>(site: Site<C>, context: C, request: Http.Request, now: i64): Option<Person>
```

The person of REQUEST at NOW (a session cookie or an API token), or undefined: what a route checks before it serves.

### `routes`

```gizlang
function routes<C>(site: Site<C>): Vec<Http.Route<App.Handle<C>>>
```

The sign-in of an app in one call: `routes.push(...Auth.routes(site))` serves PREFIX/sign-in (the page, and the password
sign-in when PASSWORD is on), PREFIX/link (a mailed one-use link, which also makes the account of a new address) and
PREFIX/sign-out. Call `Auth.install` on the database once first.

## Constants

### `SIGN_IN_FAILED`

```gizlang
const SIGN_IN_FAILED = "The email or the password is wrong."
```

The answer of every sign-in that fails: the same for an unknown address and a wrong password.

### `API_PREFIX`

```gizlang
const API_PREFIX = "t."
```

The prefix of an API token. A token without it is a session (opaque, "s.") or gizstack's signed form.

### `COOKIE`

```gizlang
const COOKIE = Sessions.COOKIE
```

The cookie that holds a session, and the parts of the identity an app uses on its own: teams and their Gate, the provider
sign-in, and the passkey challenge.

