Add Authentication and Scopes wiki page
1 parent
f3c96e25ed
commit
f82a13fc88
1 file changed
+72
@@ -0,0 +1,72 @@
|
|||||||
|
# Authentication & Scopes
|
||||||
|
|
||||||
|
familiar authenticates to EVE Online through **EVE SSO** using the **PKCE** flow (no client secret), and stores credentials for **many characters** in one encrypted file. This page covers the flow, the storage, and the full scope list.
|
||||||
|
|
||||||
|
Source: [`auth.py`](https://git.hiddenden.cafe/Hiddenden/familiar/src/branch/main/src/familiar/auth.py) and [`config.py`](https://git.hiddenden.cafe/Hiddenden/familiar/src/branch/main/src/familiar/config.py).
|
||||||
|
|
||||||
|
## The login flow (PKCE)
|
||||||
|
|
||||||
|
`familiar login` runs `interactive_login()`:
|
||||||
|
|
||||||
|
1. Generate a PKCE `code_verifier` / `code_challenge` (S256) and a random `state`.
|
||||||
|
2. Build the EVE SSO authorize URL for the configured app + scopes and open the browser.
|
||||||
|
3. Run a tiny local HTTP server on `localhost:8765/callback` to capture the returned `code` and `state`.
|
||||||
|
4. Verify `state` matches (CSRF guard) — abort if not.
|
||||||
|
5. Exchange the `code` for tokens (PKCE, **no client secret**).
|
||||||
|
6. Decode the access token's JWT claims to get the character id (`sub`), name, and granted scopes — and persist the bundle.
|
||||||
|
|
||||||
|
Because it's PKCE, the EVE application's **Client ID is not a secret** and ships as a config default.
|
||||||
|
|
||||||
|
## Token storage
|
||||||
|
|
||||||
|
- Credentials are a **dict of characters keyed by id**: `{ "characters": { "<id>": <bundle>, ... } }`.
|
||||||
|
- The whole store is **Fernet-encrypted** (symmetric key in a sibling `key` file) and written with restricted permissions (`0o600` where supported).
|
||||||
|
- A **legacy single-character file** is automatically migrated to the multi-character format on load.
|
||||||
|
- Each bundle holds the rotating `refresh_token`, the current `access_token`, `expires_at`, the character id/name, and the granted scopes.
|
||||||
|
|
||||||
|
## Token refresh
|
||||||
|
|
||||||
|
The MCP server never logs in interactively — it only calls `get_auth(character_id)`:
|
||||||
|
|
||||||
|
- If the cached access token is still valid (> 60s from expiry), return it.
|
||||||
|
- Otherwise use the **rotating refresh token** to get a fresh access token (and a new refresh token), save the updated bundle, and return the new access token.
|
||||||
|
|
||||||
|
## Multiple characters
|
||||||
|
|
||||||
|
Run `familiar login` once per character (switch EVE accounts in the browser between runs) — they all live in one store. Helpers:
|
||||||
|
|
||||||
|
- `list_characters()` — id, name, scopes for each, sorted by name.
|
||||||
|
- `resolve_character(name_or_id)` — maps a name or id to a logged-in character id.
|
||||||
|
- `remove_character(name_or_id | None)` — forget one character, or all.
|
||||||
|
|
||||||
|
This is what lets authenticated read tools default to running across **all** logged-in characters (see the per-character pattern in **[Architecture](Architecture)**).
|
||||||
|
|
||||||
|
> Changing the requested scopes requires logging in again — the granted scopes are baked into the stored token.
|
||||||
|
|
||||||
|
## Scopes
|
||||||
|
|
||||||
|
familiar requests **73** scopes split into read and write sets in `config.py`. The split lets a caller opt into a read-only subset (via `FAMILIAR_SCOPES`) while the default grants the full set. **All requested scopes must also be enabled on the EVE application itself.**
|
||||||
|
|
||||||
|
### Read scopes (selected highlights)
|
||||||
|
|
||||||
|
`publicData`, plus character scopes for location/online/ship, clones & implants, fatigue, skills & skill queue, wallet, assets, industry & mining jobs, market orders, contracts, blueprints, contacts, standings, loyalty, medals, titles, agents research, chat channels, notifications, FW stats, freelance jobs, corp roles, mail, calendar, fittings, fleet, killmails, activities, access lists; structure/universe/market scopes (`search_structures`, `read_structures`, structure markets, customs offices); alliance contacts; and the full set of **corp** read scopes (membership, member tracking, divisions, titles, medals, standings, contacts, structures, starbases, facilities, container logs, blueprints, FW stats, projects, freelance jobs, corp wallet(s), corp assets, corp industry & mining jobs, corp orders, corp contracts, corp killmails).
|
||||||
|
|
||||||
|
### Write scopes
|
||||||
|
|
||||||
|
These power the opt-in write actions (see **[Write Safety](Write-Safety)**):
|
||||||
|
|
||||||
|
| Scope | Enables |
|
||||||
|
|-------|---------|
|
||||||
|
| `esi-mail.organize_mail.v1` | mark mail read/unread |
|
||||||
|
| `esi-mail.send_mail.v1` | send mail |
|
||||||
|
| `esi-calendar.respond_calendar_events.v1` | respond to calendar events |
|
||||||
|
| `esi-characters.write_contacts.v1` | add/remove contacts |
|
||||||
|
| `esi-fittings.write_fittings.v1` | create/delete fittings |
|
||||||
|
| `esi-fleets.write_fleet.v1` | fleet invite / update |
|
||||||
|
| `esi-ui.open_window.v1` | open in-game windows |
|
||||||
|
| `esi-ui.write_waypoint.v1` | set autopilot waypoints |
|
||||||
|
| `esi-planets.manage_planets.v1` | PI (read + write) |
|
||||||
|
|
||||||
|
## EVE application
|
||||||
|
|
||||||
|
The app is registered on [developers.eveonline.com](https://developers.eveonline.com/). Its Client ID, callback host/port (`localhost:8765`), and SSO endpoints are all defined in `config.py` and overridable by environment variable — see **[Configuration](Configuration)**.
|
||||||
Reference in new issue
Block a user