mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
139 lines
6.3 KiB
Markdown
139 lines
6.3 KiB
Markdown
# Auth architecture overview
|
||
|
||
This document consolidates how bitvid authentication works today, with a focus on
|
||
`js/services/authService.js` and the provider implementations in
|
||
`js/services/authProviders/`. It complements the storage details in
|
||
[`docs/nostr-auth.md`](nostr-auth.md) and the remote signer specifics in
|
||
[`docs/nip46-remote-signers.md`](nip46-remote-signers.md).
|
||
|
||
## Core building blocks
|
||
|
||
- **AuthService (`js/services/authService.js`)** orchestrates login/logout flows,
|
||
maintains the active identity, updates saved profile storage, and emits auth
|
||
events for the rest of the app.
|
||
- **Auth providers (`js/services/authProviders/`)** are pluggable adapters that
|
||
implement `login()` for a specific signing strategy:
|
||
- `nip07` (browser extension signer)
|
||
- `nsec` (direct/private key signer stored locally)
|
||
- `nip46` (remote signer via Nostr Connect)
|
||
- **State + storage** lives in `js/state/appState.js` and `js/state/cache.js`,
|
||
backed by `localStorage` keys described in `docs/nostr-auth.md`.
|
||
|
||
## AuthService responsibilities
|
||
|
||
### Provider selection and normalization
|
||
|
||
`AuthService.requestLogin()` is the entry point for logins. It:
|
||
|
||
1. Normalizes the requested provider id (defaults to `nip07`).
|
||
2. Calls the provider’s `login()` method with the active `nostrClient` and
|
||
provider-specific options.
|
||
3. Normalizes the provider result into `{ pubkey, authType, signer }`.
|
||
4. For NIP-07, requests extension permissions before continuing.
|
||
5. Either returns the normalized result (when `autoApply: false`) or calls
|
||
`login()` to apply the identity.
|
||
|
||
### Applying a login
|
||
|
||
`AuthService.login(pubkey, options)` is responsible for applying the session:
|
||
|
||
- **Identity + session state**
|
||
- Normalizes the pubkey to hex, writes it to `appState` (`setPubkey`) and
|
||
stores the bech32 `npub` (`setCurrentUserNpub`).
|
||
- Updates `nostrClient.pubkey` so downstream services use the new identity.
|
||
- **Saved profile persistence**
|
||
- Reads + updates the saved profile list in `js/state/cache.js`.
|
||
- Persists `bitvid:savedProfiles:v1` with the latest `authType` + `providerId`.
|
||
- Ensures there is an `activePubkey` entry when `persistActive` is true.
|
||
- **Post-login hydration**
|
||
- Kicks off async profile/block/relay loading via `applyPostLoginState()` and
|
||
emits `auth:post-login` for consumers (UI updates, etc.).
|
||
|
||
### Logout and profile switching
|
||
|
||
- `logout()` clears the active pubkey/npub, resets moderation + caches, and
|
||
keeps the saved profile list intact so users can quickly re-auth.
|
||
- `switchProfile()` replays the login flow for a previously saved pubkey and
|
||
moves it to the front of the saved list.
|
||
|
||
## Provider flows
|
||
|
||
### NIP-07 (browser extension signer)
|
||
|
||
- Implemented by `js/services/authProviders/nip07.js`.
|
||
- Delegates `login()` to `nostrClient.login()` and expects a pubkey (and optional
|
||
signer) in the result.
|
||
- After provider login, `AuthService` requests extension permissions before
|
||
completing the session. Permission failure aborts the login.
|
||
|
||
**Key behavior:** signing stays inside the browser extension; bitvid only stores
|
||
pubkey metadata in `localStorage`.
|
||
|
||
### nsec (local signer)
|
||
|
||
- Implemented by `js/services/authProviders/nsec.js`.
|
||
- Supports two modes:
|
||
- **Unlock stored key** (`unlockStored: true`): uses
|
||
`nostrClient.unlockStoredSessionActor()` and requires a passphrase.
|
||
- **Direct secret**: derives a key from an `nsec`, hex key, or seed via
|
||
`nostrClient.derivePrivateKeyFromSecret()` and registers a local signer with
|
||
`nostrClient.registerPrivateKeySigner()`.
|
||
- Can optionally persist the encrypted key on the device; authService still only
|
||
stores public metadata in the saved profile list.
|
||
|
||
**Key behavior:** signing happens locally in the browser with a derived private
|
||
key; storage of the private key is optional and encrypted when persisted.
|
||
|
||
### NIP-46 (remote signer / Nostr Connect)
|
||
|
||
- Implemented by `js/services/authProviders/nip46.js`.
|
||
- Supports three paths:
|
||
- **Reuse stored session** (`reuseStored: true`): use
|
||
`nostrClient.useStoredRemoteSigner()` to resume the saved NIP-46 session.
|
||
- **Manual connection** (`mode: "manual"`): use a provided
|
||
`connectionString` (e.g., `nostrconnect://` or `bunker://`).
|
||
- **Handshake flow** (`mode: "handshake"`, default): generate a handshake via
|
||
`nostrClient.prepareRemoteSignerHandshake()` and then connect using the
|
||
returned connection string + client keypair.
|
||
|
||
**Key behavior:** signing happens on a remote device. Session material is stored
|
||
in `bitvid:nip46:session:v1` as described in
|
||
[`docs/nip46-remote-signers.md`](nip46-remote-signers.md).
|
||
|
||
## Session state + persistence
|
||
|
||
Auth state is intentionally small and split across caches:
|
||
|
||
- **Active identity:** `js/state/appState.js` keeps the current `pubkey` + `npub`
|
||
in memory and updates `nostrClient.pubkey` on login.
|
||
- **Saved profiles:** `js/state/cache.js` manages
|
||
`bitvid:savedProfiles:v1`, including `authType` + `providerId` for each entry.
|
||
See [`docs/nostr-auth.md`](nostr-auth.md) for the schema and migration notes.
|
||
- **Profile cache:** `bitvid:profileCache:v1` is used to show display names +
|
||
avatars quickly; it is updated during `loadOwnProfile()` calls.
|
||
- **Remote signer session:** `bitvid:nip46:session:v1` stores handshake/session
|
||
data for NIP-46 reconnects. See
|
||
[`docs/nip46-remote-signers.md`](nip46-remote-signers.md) for details.
|
||
|
||
## NIP-04 / NIP-44 considerations
|
||
|
||
AuthService and the provider adapters do **not** implement NIP-04 or NIP-44
|
||
message encryption/decryption directly. They simply supply a pubkey and (when
|
||
available) a signer object back to the caller. When other features (like direct
|
||
messages) need NIP-04 or NIP-44 capabilities, they rely on the active signer
|
||
implementation on the `nostrClient`. Remote signers and extensions must support
|
||
those encryption methods for DM features to work, while local `nsec` signers can
|
||
provide the primitives directly.
|
||
|
||
Signing/encryption requests always flow through the signer adapter registry in
|
||
`js/nostr/client.js` (accessed via `js/nostrClientFacade.js`). The registry
|
||
selects the active signer, falls back to the strongest supported capability, and
|
||
triggers permission prompts (for example, the NIP-07 extension handshake) before
|
||
attempting privileged calls.
|
||
|
||
## Related docs
|
||
|
||
- [`docs/nostr-auth.md`](nostr-auth.md)
|
||
- [`docs/nip46-remote-signers.md`](nip46-remote-signers.md)
|
||
- [`docs/signing-adapter.md`](signing-adapter.md)
|