# Authentication

| Server | Who gets in | Whose name a commit carries |
| --- | --- | --- |
| Local | Whoever holds the bearer printed at start | The board checkout's git user |
| Hosted account server | People signed in with GitHub, choosing their connected repositories | The signed-in person; the server commits |
| SQLite source | GitHub sign-in with its own reader/writer policy, or explicit workspace bearer access | The signed-in person; standalone bearer mode uses the SQLite service identity |

## Local: one bearer per start

The local server prints a random 256-bit token on every start and asks for it
as `Authorization: Bearer <token>` on every route except the editor script.
It answers loopback only and commits as the board checkout's git user.
[Edit the board in the browser](/docs/guides/live#the-server-answers-loopback-only)
lists every limit.

## Authentication is independent of storage

[SQLite](/docs/deployment/sqlite) can use the same GitHub login as repository sources. `board.auth.provider` chooses sign-in independently of `board.store` and `board.sources`. Database access comes from its own readers and writers, checked on every request.

Explicit `provider: token` selects standalone access on loopback or behind HTTPS.
The token grants access to one database workspace; server read-only mode
disables writes. HTTPS servers read the bearer from an environment variable.
The browser uses `kanban.api.auth: token`, keeps the credential in session
storage for that API and disconnects when authorization is refused.

## Hosted: your GitHub account and its connected repositories

A hosted server defaults to account mode (`FOLIO_BOARD_MULTI_REPO=true`).
People sign in through one GitHub App. Sign-in identifies the person; it does not check access to the
repository that hosts Folio Board.

1. **Sign in with GitHub** goes through `/auth/login` and `/auth/callback`.
2. A one-time code, valid 60 seconds, returns to the board. `/auth/exchange`
   exchanges it for a session, valid up to 8 hours.
3. The board loads cards from every source configured by this account in this
   browser. An existing session supplies the first source when no configuration
   exists. The server checks each source before returning its cards. On a first
   visit without a source, or when none can be read, the entry page offers source
   configuration.
4. Open the profile photo, then **Settings → Sources**, to add, edit or remove
   sources. A repository's `board` branch is tried first, otherwise the `board`
   folder on its default branch. **Branch and folder** opens another location.
   **Connect repositories** opens the App's installation screen; **Refresh
   sources** updates the available repositories after installation.

Every loaded card carries its source. The existing `source:` and `project:`
filters control which cards are visible; adding a source does not switch the
canvas or discard its filter. Writes go to that card's own source, with its
repository permissions. Identical card ids in different sources remain distinct.

Choosing a source opens existing files; it does not initialize a repository.
Configured sources and view preferences are scoped to this account in this browser.
Remembering a source grants no access: every reopening goes through the server.
When an account session expires, the board reconnects through
GitHub automatically and returns to the same page, sources and saved view.
If another tab already has a fresh session, it uses that session first. Repeated
sign-in failures stop automatic navigation and offer a retry; connection errors
do not log the person out. This uses the existing eight-hour sign-in flow,
without storing GitHub credentials in the browser or replaying card writes.
[Deployment modes](/docs/deployment) compares what each mode can save and how
it authenticates.

The browser receives a signed session with an opaque credential handle, never
GitHub's access token. GitHub credentials are encrypted in the persistent authorization database. Each account
has its own clone for each selected branch and directory. Git reads and pushes
use that person's GitHub App user access token, so they cannot exceed either
the person's or the App's access.

Repository access is checked on every request. Removing a repository from the
installation or removing the person's access stops subsequent reads and writes.
Read permission opens the board; push permission enables edits. Every commit
names the signed-in person as author and the server as committer.

**Sign out** invalidates all board sessions from that sign-in. Named API tokens
have independent handles and must be revoked in Settings. Restarts retain
authorized credentials when the authorization database and signing key are
preserved on persistent storage.

The App must allow installation by **Any account** for people outside the
owner's account to connect repositories. A private App cannot provide that
flow. Organizations may require an administrator to approve its installation.
[Deploy a hosted board](/docs/deployment/deploy) lists the setup.

The server still validates its public Host, its allowed page origins, the
signed OAuth state and the session on every request. No session is returned in
a URL: the one-time code is consumed once.

## Hosted with one configured repository

With `FOLIO_BOARD_MULTI_REPO=false`, `board.store.repo`, `ref` and `path`
select one board for the whole server. Only collaborators can read it. This
mode uses an installation token from the App's private key, or the personal
access token named by `board.store.token_env`, for its git operations.

## Tools use their own tokens

[Settings → API tokens](/docs/deployment/tokens) issues expiring, revocable access
to one source for the remote CLI and [MCP](/docs/deployment/mcp). These credentials
do not replace the normal web login and cannot manage account settings.

[Authorization storage](/docs/deployment/authorization) selects SQLite or
standard Postgres for sessions, encrypted credentials and token revocations.
This choice is independent of the source providers and login method.
