docs: document plugin vs backend authentication boundaries
Clarify that the native Daily Notification Plugin does not authenticate users or call notification-wakeup-service directly. Authentication belongs in the host app; the plugin only schedules local notifications and orchestrates host-provided content fetch. Add docs/security-boundaries.md with responsibility matrix, auth flow diagram, SPI boundary notes, and a warning against adding backend auth logic to the plugin layer.
This commit is contained in:
228
docs/security-boundaries.md
Normal file
228
docs/security-boundaries.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# Security Boundaries — Native Plugin vs Backend Auth
|
||||
|
||||
**Purpose:** Document intentional architectural boundaries so
|
||||
contributors do not add backend authentication into the plugin layer.
|
||||
|
||||
**Owner:** Development Team
|
||||
**Last Updated:** 2026-05-20
|
||||
**Status:** active
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The **Daily Notification Plugin** is a **local notification
|
||||
orchestration layer**. It schedules alarms, manages permissions, caches
|
||||
content for offline delivery, and invokes **host-provided** fetch logic
|
||||
when configured.
|
||||
|
||||
It is **not** an authentication client and **not** a backend service
|
||||
client for TimeSafari identity or session management.
|
||||
|
||||
**Authentication belongs in the host app**, which talks to
|
||||
**notification-wakeup-service**. The plugin must never own that flow.
|
||||
|
||||
---
|
||||
|
||||
## Responsibility Matrix
|
||||
|
||||
| Concern | Plugin | Host app | Backend
|
||||
(notification-wakeup-service) |
|
||||
| --- | --- | --- | --- |
|
||||
| User login / session | No | Yes | Yes |
|
||||
| JWT / token issuance | No | Yes (or via backend) | Yes |
|
||||
| Token refresh | No | Yes | Yes |
|
||||
| DID / identity selection | No | Yes | May validate |
|
||||
| Schedule local notifications | Yes | Configures via API | No |
|
||||
| OS permission prompts | Yes | May explain UX | No |
|
||||
| Local SQLite / cache | Yes | No | No |
|
||||
| Prefetch timing (WorkManager, BG tasks) | Yes | No | No |
|
||||
| Fetch notification **content** | Orchestrates only | Implements fetcher | Serves API data |
|
||||
| Business API contracts | No | Yes | Yes |
|
||||
|
||||
---
|
||||
|
||||
## Layer Responsibilities
|
||||
|
||||
### Plugin (`@timesafari/daily-notification-plugin`)
|
||||
|
||||
The plugin **does**:
|
||||
|
||||
- Schedule and cancel **local** notifications (AlarmManager,
|
||||
UNUserNotificationCenter, etc.).
|
||||
- Persist schedules, cached content, and delivery metadata locally.
|
||||
- Run background **prefetch orchestration** (when to fetch, retries,
|
||||
TTL-at-fire).
|
||||
- Request and track **notification permission** status.
|
||||
- Expose a **Service Provider Interface (SPI)** so the host app can
|
||||
supply content in native code (`NativeNotificationContentFetcher`).
|
||||
- Forward **already-obtained** credentials to a registered native
|
||||
fetcher via `configureNativeFetcher()` (passthrough only; see below).
|
||||
- Perform **generic HTTP GET** only when a schedule supplies an
|
||||
explicit `contentFetch.url` (no login, no token refresh, no
|
||||
TimeSafari-specific auth).
|
||||
|
||||
The plugin **does not**:
|
||||
|
||||
- Authenticate users.
|
||||
- Communicate with **notification-wakeup-service** or other backend
|
||||
auth endpoints **as an auth client**.
|
||||
- Sign JWTs, manage refresh tokens, or implement OAuth/OIDC flows.
|
||||
- Encode TimeSafari-specific identity or API contracts in plugin code.
|
||||
|
||||
### Backend (`notification-wakeup-service` and related APIs)
|
||||
|
||||
The backend **does**:
|
||||
|
||||
- Authenticate users and establish sessions (exact mechanism is owned
|
||||
by the TimeSafari platform).
|
||||
- Issue, validate, and refresh credentials used for API access.
|
||||
- Expose wakeup / notification-related APIs consumed by the **app**,
|
||||
not by the plugin directly.
|
||||
|
||||
The backend **does not**:
|
||||
|
||||
- Depend on the Capacitor plugin for login or session lifecycle.
|
||||
- Assume the plugin will call auth endpoints on its own.
|
||||
|
||||
### Host app (TimeSafari / consuming Capacitor application)
|
||||
|
||||
The app **does**:
|
||||
|
||||
- Authenticate the user against **notification-wakeup-service**
|
||||
(and any related identity services).
|
||||
- Obtain and refresh tokens **before** background fetch runs.
|
||||
- Register `NativeNotificationContentFetcher` in native code and
|
||||
implement `fetchContent()` using app-owned HTTP clients and auth.
|
||||
- Call plugin APIs to configure schedules, permissions, and optional
|
||||
`configureNativeFetcher()` with **pre-generated** tokens from app code.
|
||||
- Handle auth failures (401/403), logout, and identity changes without
|
||||
expecting the plugin to recover sessions.
|
||||
|
||||
The app **does not**:
|
||||
|
||||
- Assume the plugin will log in or refresh credentials on its behalf.
|
||||
|
||||
---
|
||||
|
||||
## Authentication Flow (Authoritative)
|
||||
|
||||
Authentication **does not** go through the plugin.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant App as Host app
|
||||
participant Auth as notification-wakeup-service
|
||||
participant Plugin as Daily Notification Plugin
|
||||
participant OS as OS notification APIs
|
||||
|
||||
User->>App: Sign in / unlock identity
|
||||
App->>Auth: Authenticate (credentials, DID, etc.)
|
||||
Auth-->>App: Session / tokens
|
||||
App->>App: Build or obtain JWT for API fetch
|
||||
App->>Plugin: configureNativeFetcher(tokens from app)
|
||||
App->>Plugin: registerNativeFetcher(app implementation)
|
||||
Plugin->>Plugin: Schedule prefetch / notify alarms
|
||||
Plugin->>App: NativeNotificationContentFetcher.fetchContent()
|
||||
Note over App: App uses tokens from Auth;<br/>not plugin auth logic
|
||||
App-->>Plugin: NotificationContent list
|
||||
Plugin->>OS: Show local notification
|
||||
```
|
||||
|
||||
**Rule:** `App → notification-wakeup-service` for authentication.
|
||||
The plugin sits **below** that boundary and only receives outputs the
|
||||
app chooses to pass in (e.g. a JWT string for a registered fetcher).
|
||||
|
||||
---
|
||||
|
||||
## Native Content Fetcher (SPI Boundary)
|
||||
|
||||
Background workers **cannot** rely on JavaScript bridges. The plugin
|
||||
calls **`NativeNotificationContentFetcher`**, which the **host app
|
||||
implements and registers**.
|
||||
|
||||
- **Plugin:** When to fetch, timeouts, retries, cache write, notify
|
||||
scheduling.
|
||||
- **Host fetcher:** How to call APIs, which headers to send, how to
|
||||
handle 401 and refresh **in app code**.
|
||||
|
||||
Example pattern (conceptual): the fetcher uses a token the app already
|
||||
minted; the plugin never signs JWTs. See
|
||||
`android/.../NativeNotificationContentFetcher.java` Javadoc.
|
||||
|
||||
`configureNativeFetcher()` stores or forwards `apiBaseUrl`, `activeDid`,
|
||||
and `jwtToken` supplied by the app. It is **configuration passthrough**,
|
||||
not an authentication implementation. Tokens are **not** persisted by
|
||||
default (`persistToken` defaults to `false`).
|
||||
|
||||
---
|
||||
|
||||
## Explicit Non-Goals (Plugin)
|
||||
|
||||
The following are **intentionally out of scope** for this repository:
|
||||
|
||||
1. **User authentication** — no login UI, no credential storage for
|
||||
platform identity, no session store tied to wakeup-service.
|
||||
2. **Direct backend auth traffic** — the plugin must not implement
|
||||
clients for `notification-wakeup-service` auth/login/refresh routes.
|
||||
3. **Backend business logic** — plans, offers, projects, and community
|
||||
rules live in app + backend, not in the plugin.
|
||||
|
||||
The plugin’s job is **local reliability**: prefetch → cache → schedule →
|
||||
display.
|
||||
|
||||
---
|
||||
|
||||
## Warning — Do Not Add Backend Auth to the Plugin
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ DO NOT add backend authentication logic to the plugin │
|
||||
│ layer (TypeScript bridge, Android Kotlin/Java, iOS Swift). │
|
||||
│ │
|
||||
│ Wrong: JWT signing, refresh flows, or HTTP clients to │
|
||||
│ notification-wakeup-service auth endpoints inside │
|
||||
│ DailyNotificationPlugin / FetchWorker / iOS plugin│
|
||||
│ │
|
||||
│ Right: Implement auth in the host app; register a native │
|
||||
│ fetcher; pass short-lived tokens from app code. │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Why this matters:**
|
||||
|
||||
- **Security:** Auth secrets and refresh logic stay in one place (the
|
||||
app), subject to app review and platform keychains.
|
||||
- **Coupling:** The plugin stays reusable across apps and test harnesses.
|
||||
- **Background limits:** OS background tasks must stay short; auth
|
||||
refresh belongs in app lifecycle, not plugin workers.
|
||||
- **Audit clarity:** Security reviewers can treat wakeup-service + app
|
||||
as the trust boundary; the plugin is untrusted for identity.
|
||||
|
||||
If integration docs elsewhere mention “plugin provides authentication,”
|
||||
treat that as **orchestration of fetch timing**, not **identity
|
||||
authentication**. This document is the security boundary reference.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- `doc/integration/REFACTOR_NOTES.md` — SPI refactor; host-owned fetch
|
||||
- `doc/integration/REFACTOR_NOTES_QUICK_START.md` — “JWT generation in
|
||||
host app only”
|
||||
- `android/.../NativeNotificationContentFetcher.java` — SPI contract
|
||||
- `ARCHITECTURE.md` — broader system design (encryption, local storage)
|
||||
|
||||
---
|
||||
|
||||
## Assumptions & Limits
|
||||
|
||||
- **notification-wakeup-service** is named as the TimeSafari auth/wakeup
|
||||
entry point per platform architecture; endpoint details live in app
|
||||
and backend repos, not here.
|
||||
- Generic `contentFetch.url` HTTP GET in the plugin is a **legacy /
|
||||
optional** path for URL-configured schedules; new integrations should
|
||||
prefer the native fetcher SPI with app-owned auth.
|
||||
- This document does not change runtime behavior; it records existing
|
||||
intent for reviewers and implementers.
|
||||
Reference in New Issue
Block a user