# The token

Every request Theorem sends your app carries `Authorization: Bearer` and a token: a JWT
that Theorem signed for one person and your one app. Check it on every request, before
anything else. Refuse the request with 401 if any check fails.

## The claims

```json
{ "iss": "https://theorem.sa",
  "sub": "acc_01KA0A3C4D5E6F7G8H9JKMNPQR",
  "aud": "app_01KA3B3C4D5E6F7G8H9JKMNPQR",
  "email": "omar@example.com",
  "name": "Omar Al-Fahad",
  "team": { "id": "team_01KA2B3C4D5E6F7G8H9JKMNPQR", "name": "Al-Noor School",
            "leader": false,
            "roles": [ { "id": "rol_01KA2F3C4D5E6F7G8H9JKMNPQR", "name": "Finance" } ] },
  "iat": 1800000000, "exp": 1800000300 }
```

| Claim | What it is |
|---|---|
| `iss` | Who signed it: always `https://theorem.sa`. |
| `sub` | The person's account ID, `acc_` and 26 letters and digits. It never changes: key your data by it. |
| `aud` | Your app's ID, `app_` and 26 letters and digits, as the **Connections** tab shows it. |
| `email` | The address the person signs in to Theorem with. It is not their address on the team's domain. |
| `name` | The person's name. Left out for a person who has given none. |
| `team` | Your app's team, as it is now. |
| `team.id` | The team's ID, `team_` and 26 letters and digits. |
| `team.name` | The team's name. A leader may change it. |
| `team.leader` | `true` when the person leads the team. |
| `team.roles` | The team's roles the person holds, each `{ "id", "name" }`, in the team's order. `[]` for none. |
| `iat` | When it was signed, in seconds since 1970. |
| `exp` | When it ends: `iat` and 300 seconds. |

There is nothing else. The token says nothing of the person's other teams, their session
or their chat.

## Checking it

1. Read the header. `alg` is `EdDSA`, and `kid` names the key it was signed with.
2. Get Theorem's public keys from `https://theorem.sa/api/identity/jwks`. It is a JSON Web
   Key Set of Ed25519 keys (`"kty": "OKP"`, `"crv": "Ed25519"`). Keep them, and read them
   again when a token names a `kid` you don't have. If you saved them to a file, save
   them again then.
3. Check the signature with the key of that `kid`. Accept `EdDSA` only.
4. Check `iss` is `https://theorem.sa`.
5. Check `aud` is your own app's ID.
6. Check `exp` has not passed.

Most JWT libraries do all of it when you give them the keys, the issuer and the audience.
In Python with PyJWT, as the example does:

```python
keys = jwt.PyJWKClient("https://theorem.sa/api/identity/jwks")
key = keys.get_signing_key_from_jwt(token)
claims = jwt.decode(token, key.key, algorithms=["EdDSA"],
                    audience=APP_ID, issuer="https://theorem.sa")
```

## Why `aud` must be checked

Your app's ID is not a secret: your team's leaders see it. And another team can add your
app's address as its own app, so Theorem would send your app tokens for that team's people,
with that team's role names, Finance among them. Only `aud` tells those tokens apart from
your own team's: it is that other app's ID, not yours. An app that skips the check lets in
anyone from any team.

## How long it lasts

A token lasts 300 seconds, five minutes. Theorem may send the same token for several calls
until shortly before it ends, then makes a new one.

A person removed from the team, or from the role that gave them your app, gets no new
token. So the most they can still reach your app is until their last token ends: five
minutes at most. If that is too long for something, check with your own records too.

## Its size

A token names the person's roles, so it can be long: up to about 7,200 bytes for someone
holding 20 roles with 40-letter names. Make sure your server and any proxy in front of it
accept a header that size.

## What to answer when a check fails

Answer 401, with `WWW-Authenticate: Bearer`. A leader who checks the app, and anyone who
uses it, then sees that your app refused Theorem's token. Say nothing about which check failed to the caller; write it to
your own log instead, as the example does.
