docs: add comprehensive device authentication implementation details
- Add IMPLEMENTATION_EXACT.md with exact code changes for all phases
- Update IMPLEMENTATION_PLAN.md with clarifications on two-field approach:
- device_identifier: Serial number (Kobo) or UUID (KOReader)
- auth_token: Auto-generated API key for authentication
- Resolve all user questions with ✅ marked decisions
- Add verification steps for documentation accuracy
- Document Kobo vs KOReader registration workflow differences
- Add SQL query for token regeneration (UpdateDeviceAuthToken)
- Include TypeScript device management code
- Add Bruno API test files for all new endpoints
- Update Kobo setup documentation for URL path token approach
This commit is contained in:
File diff suppressed because it is too large
Load Diff
+126
-33
@@ -236,6 +236,7 @@ func (m *DeviceAuthMiddleware) Authenticate(next echo.HandlerFunc) echo.HandlerF
|
||||
- [ ] Return 401 if both methods fail
|
||||
|
||||
3. **Add Token Regeneration Backend** (`internal/handlers/devices.go`)
|
||||
- [ ] Add new SQL query: `UpdateDeviceAuthToken` (DO NOT use UpdateDevice - it doesn't modify auth_token field)
|
||||
- [ ] Add endpoint: `POST /api/devices/:id/regenerate-token`
|
||||
- [ ] Generate new random UUID for auth_token
|
||||
- [ ] Update device in database
|
||||
@@ -499,7 +500,7 @@ More secure but requires plugin installation. Justified because KOReader users a
|
||||
- `internal/handlers/devices.go` - Add regenerate token endpoint
|
||||
- `internal/database/queries/queries.sql` - No changes needed (auth_token already exists)
|
||||
- `templates/devices.templ` - Add copy token, regenerate token buttons
|
||||
- `templates/partials/device-management.templ` - Kobo config instructions with API key
|
||||
- Create `templates/devices-kobo-config.templ` - Kobo config instructions with API key
|
||||
|
||||
### Testing
|
||||
- `cmd/server/tests/kobo_test.go` - Update for URL path token
|
||||
@@ -607,6 +608,17 @@ Based on user feedback, the following decisions have been finalized:
|
||||
|
||||
**Note:** This is about device MANAGEMENT, not authentication. Authentication uses `auth_token` (API keys) for all devices. Device identifier is for tracking multiple installations of the same physical device.
|
||||
|
||||
**Clarification for Kobo Devices:**
|
||||
Kobo also uses the two-field approach, but differently:
|
||||
- **Kobo `device_identifier`**: User enters serial number manually (one-time registration)
|
||||
- **Kobo `auth_token`**: Auto-generated API key for authentication
|
||||
- **Kobo vs KOReader Difference**:
|
||||
- Kobo: User manually enters serial as device_identifier
|
||||
- KOReader: Plugin auto-generates UUID as device_identifier
|
||||
- Both: Use auto-generated auth_token for API authentication
|
||||
|
||||
**Note:** This is about device MANAGEMENT, not authentication. Authentication uses `auth_token` (API keys) for all devices. Device identifier is for tracking multiple installations of the same physical device.
|
||||
|
||||
---
|
||||
|
||||
## 16.1 Codebase Investigation: device_identifier Field
|
||||
@@ -753,20 +765,42 @@ X-Bookhoard-Device-ID: {device_identifier}
|
||||
**Phase Integration:** Implement Device ID in Phase 1 (alongside dual authentication). It's same amount of work but solves `max_devices` problem elegantly.
|
||||
|
||||
**Questions for User:**
|
||||
1. **Registration Workflow:** Should KOReader plugin self-register (user approves in browser) or require manual registration first?
|
||||
2. **Device ID Persistence:** Where does KOReader store settings?
|
||||
- `/mnt/us/koreader/settings.bookhoard.lua`?
|
||||
- System `G_Settings`?
|
||||
- This determines if Device ID survives plugin updates
|
||||
3. **max_devices Behavior:**
|
||||
- Should each Device ID count as 1 device (recommended)?
|
||||
- Or limit tokens per Device ID (more complex)?
|
||||
4. **Backward Compatibility:**
|
||||
- How to handle existing KOReader installations without Device ID?
|
||||
- Force re-registration? Auto-migrate?
|
||||
5. **KOReader Plugin Repo:**
|
||||
- Does `github.com/bookhoard/koreader-plugin` exist?
|
||||
- Should Device ID generation happen there, or in main Bookhoard repo?
|
||||
|
||||
✅ **RESOLVED**: Kobo two-field approach clarified (serial + API key)
|
||||
- Kobo: Manual serial entry (device_identifier) + auto-generated API key (auth_token)
|
||||
- KOReader: Auto-generated UUID (device_identifier) + auto-generated API key (auth_token)
|
||||
- Documentation updated to reflect this distinction
|
||||
|
||||
1. ✅ **Registration Workflow:** KOReader plugin will **self-register** (user approves in browser)
|
||||
- Plugin auto-generates device_identifier on first launch
|
||||
- Plugin calls Bookhoard registration API with device_identifier
|
||||
- User approves device in Bookhoard web UI
|
||||
- Plugin receives auth_token and stores it locally
|
||||
- One-time setup with approval workflow
|
||||
2. ✅ **Device ID Persistence:** KOReader uses `G_reader_settings` (global settings object)
|
||||
- Settings persisted to `koreader/settings.reader.lua` in the main koreader directory
|
||||
- **Survives plugin updates** because settings file is separate from plugin files
|
||||
- Device ID stored as `bookhoard_device_id` key
|
||||
- Plugin directory can be replaced/updated without losing device identity
|
||||
- Standard KOReader pattern used by Wallabag, Calibre, and other sync plugins
|
||||
- Alternative considered: Plugin-specific file in `koreader/plugins/bookhoard/settings.lua` (also survives updates, but G_reader_settings is simpler)
|
||||
3. ✅ **max_devices Behavior:** Each device_identifier counts as **1 device** (same as Kobo)
|
||||
- Example: User has 3 Kindles with KOReader = 3 device registrations
|
||||
- Reinstalling KOReader on same device reuses same device_identifier (from persisted settings)
|
||||
- Reinstallation does NOT count as new device (settings file retained)
|
||||
- User can regenerate auth_token without changing device_identifier
|
||||
- Enforces user's max_devices limit accurately
|
||||
4. ✅ **Backward Compatibility:** **Not required**
|
||||
- Per @PROJECT_GUIDELINES.md: Application has never been deployed to production
|
||||
- No existing KOReader installations to migrate
|
||||
- Clean slate implementation - no legacy support needed
|
||||
- All device registrations will use new self-registration flow from day one
|
||||
5. ✅ **KOReader Plugin Repo:** Plugin does not yet exist
|
||||
- Device ID generation will happen **in the plugin** (not in main Bookhoard repo)
|
||||
- Plugin generates UUID on first launch and stores in local settings
|
||||
- Repository to be created: `github.com/bookhoard/koreader-plugin`
|
||||
- Plugin handles all KOReader-specific logic (device ID gen, API calls, UI)
|
||||
- Bookhoard backend provides generic device registration endpoints only
|
||||
|
||||
---
|
||||
|
||||
@@ -953,6 +987,9 @@ This implementation plan emerged from a detailed analysis of the current authent
|
||||
### Immediate Actions (When Ready to Proceed)
|
||||
|
||||
1. **Review this plan** - Ensure all decisions and context are captured
|
||||
- **NEW**: Review updated clarification on two-field approach (device_identifier vs auth_token)
|
||||
- **NEW**: Confirm understanding that Kobo requires manual serial entry (device_identifier)
|
||||
- **NEW**: Confirm understanding that auth_token (API key) is auto-generated for both Kobo and KOReader
|
||||
2. **Create KOReader plugin repo** - Set up `github.com/bookhoard/koreader-plugin`
|
||||
3. **Begin Phase 1** - Enhanced DeviceAuthMiddleware
|
||||
4. **Parallel development** - Kobo and KOReader tracks
|
||||
@@ -1015,9 +1052,48 @@ Based on codebase analysis, the following documentation updates are needed:
|
||||
- Shows full URL format with token
|
||||
|
||||
**Verification Needed:**
|
||||
- Confirm lines 37-53 (device registration) don't mention entering serial number
|
||||
- Verify registration flow describes automatic API key generation
|
||||
- Ensure "Copy Full Sync URL" button is documented
|
||||
- Confirm lines 37-53 correctly show TWO-FIELD approach:
|
||||
1. **device_identifier**: Serial number (user enters manually - identifies WHICH device)
|
||||
2. **auth_token**: API key (auto-generated - authenticates API requests)
|
||||
- Verify registration flow explains:
|
||||
- User enters serial number as device_identifier (step 1: "Find Your Kobo Serial Number")
|
||||
- System generates auth_token (API key) after registration
|
||||
- User copies full sync URL with auth_token (not device_identifier)
|
||||
- Ensure "Copy Full Sync URL" button displays auth_token (API key), not device_identifier (serial number)
|
||||
- Clarify in documentation that serial number is ONLY for device identity during registration
|
||||
- Auth token (API key) is what user copies for Kobo configuration
|
||||
|
||||
**IMPORTANT: Two-Field Distinction for Kobo Devices**
|
||||
|
||||
The Kobo setup uses TWO separate database fields that serve different purposes:
|
||||
|
||||
1. **`device_identifier`** (Device Identity - User Entered)
|
||||
- **Purpose**: Identify WHICH physical device this is
|
||||
- **User Action**: Manually enter Kobo serial number (e.g., "N1234567890123")
|
||||
- **Storage**: VARCHAR(255) UNIQUE NOT NULL
|
||||
- **Persistence**: Remains constant for device lifetime
|
||||
- **Example**: "N1234567890123"
|
||||
- **Used For**: Preventing duplicate registrations, tracking device identity
|
||||
|
||||
2. **`auth_token`** (API Key - System Generated)
|
||||
- **Purpose**: Authenticate API requests from this device
|
||||
- **User Action**: Auto-generated by backend during registration, copied for configuration
|
||||
- **Storage**: VARCHAR(255) UNIQUE NOT NULL
|
||||
- **Persistence**: Can be revoked and regenerated without changing device_identifier
|
||||
- **Example**: "dev_550e8400-e29b-41d4-a716-446655440000"
|
||||
- **Used For**: Kobo sync URL, OPDS access, authentication
|
||||
|
||||
**Why Two Fields?**
|
||||
- **Security**: `auth_token` can be revoked/regenerated if compromised
|
||||
- **Flexibility**: Same physical device can get new tokens without re-registration
|
||||
- **Tracking**: `device_identifier` persists across token regenerations
|
||||
- **User Experience**: Register once with serial, regenerate tokens as needed
|
||||
|
||||
**What This Means for Documentation:**
|
||||
- ✅ Step 1 (lines 37-43): Should show user finding/entering serial number (CORRECT)
|
||||
- ✅ Step 2 (lines 45-72): Should show serial entered in device_identifier field (CORRECT)
|
||||
- ✅ Configuration (lines 102-149): Should use auth_token in sync URL (NOT serial number)
|
||||
- ✅ Sync URL format: `http://IP:8765/api/sync/kobo/{auth_token}` (serial not used)
|
||||
|
||||
### New Documentation: security.md
|
||||
**Required Content:**
|
||||
@@ -1167,8 +1243,9 @@ func (h *Handlers) RegenerateDeviceToken(c echo.Context) error {
|
||||
|
||||
newToken := fmt.Sprintf("dev_%s", uuid.New().String())
|
||||
|
||||
_, err = h.db.UpdateDevice(c.Request().Context(), database.UpdateDeviceParams{
|
||||
ID: pgtype.UUID{Bytes: deviceID.Bytes(), Valid: true},
|
||||
// Use new query (to be created in queries.sql)
|
||||
_, err = h.db.UpdateDeviceAuthToken(c.Request().Context(), database.UpdateDeviceAuthTokenParams{
|
||||
ID: pgtype.UUID{Bytes: [16]byte(deviceID), Valid: true},
|
||||
AuthToken: pgtype.Text{String: newToken, Valid: true},
|
||||
})
|
||||
|
||||
@@ -1237,22 +1314,22 @@ http://IP:8765/opds/devices/{DEVICE_ID}/catalog
|
||||
**Phase 1 Tasks:**
|
||||
|
||||
1. **[CORE]** Implement enhanced DeviceAuthMiddleware with multi-method auth:
|
||||
- Try Bearer token from Authorization header (KOReader, API clients)
|
||||
- Try URL path parameter: `c.Param("token")` (Kobo sync)
|
||||
- Try query parameter: `c.QueryParam("token")` (OPDS access)
|
||||
- All methods lookup device via `GetDeviceByAuthToken`
|
||||
- Set device context on successful auth
|
||||
- Try Bearer token from Authorization header (KOReader, API clients)
|
||||
- Try URL path parameter: `c.Param("token")` (Kobo sync)
|
||||
- Try query parameter: `c.QueryParam("token")` (OPDS access)
|
||||
- All methods lookup device via `GetDeviceByAuthToken`
|
||||
- Set device context on successful auth
|
||||
|
||||
2. **[CORE]** Update Kobo routing to use path parameter:
|
||||
- Change route from `/api/sync/kobo` to `/api/sync/kobo/:token`
|
||||
- All Kobo sync endpoints inherit token from path
|
||||
- Update handler to use path parameter
|
||||
- Change route from `/api/sync/kobo` to `/api/sync/kobo/:token`
|
||||
- All Kobo sync endpoints inherit token from path
|
||||
- Update handler to use path parameter
|
||||
|
||||
3. **[CORE]** Add token regeneration endpoint:
|
||||
- Create SQL query: `UpdateDeviceAuthToken(id, auth_token)`
|
||||
- Add handler: `POST /api/devices/:id/regenerate-token`
|
||||
- Generate new API key, update database
|
||||
- Return new token to user
|
||||
- Create new SQL query: `UpdateDeviceAuthToken(id, auth_token)` (NOT UpdateDevice - it doesn't modify auth_token)
|
||||
- Add handler: `POST /api/devices/:id/regenerate-token`
|
||||
- Generate new API key, update database
|
||||
- Return new token to user
|
||||
|
||||
4. **[CRITICAL]** Update kobo-setup.md documentation:
|
||||
- Remove Username/Password references (if any remain)
|
||||
@@ -1313,4 +1390,20 @@ http://IP:8765/opds/devices/{DEVICE_ID}/catalog
|
||||
|
||||
**Plan Status**: ✅ Corrections Applied - Plan is now accurate and ready for implementation
|
||||
|
||||
**Summary**: Original plan was 95% solid with 3 minor inaccuracies about existing code. Core strategy (api-key auth for Kobo, Bearer for KOReader) remains unchanged and is the correct approach.
|
||||
**Summary**: Original plan was 95% solid. Added critical clarifications:
|
||||
|
||||
1. **Two-Field Approach for Kobo**:
|
||||
- `device_identifier` (serial): User enters manually, identifies WHICH device
|
||||
- `auth_token` (API key): Auto-generated, authenticates API requests
|
||||
- Users enter serial ONCE during registration, then use auto-generated API key for configuration
|
||||
|
||||
2. **Verification Step Correction**:
|
||||
- Changed from: "Confirm lines 37-53 don't reference entering serial number"
|
||||
- Changed to: "Confirm lines 37-53 correctly show two-field approach (serial + generated token)"
|
||||
- Serial entry is CORRECT and REQUIRED for Kobo
|
||||
|
||||
3. **Core Strategy (Unchanged)**:
|
||||
- Kobo: API key in URL path (works with stock firmware)
|
||||
- KOReader: Bearer token in header (via plugin)
|
||||
- Both: Use revocable `auth_token` for authentication
|
||||
- OPDS: Support both methods
|
||||
|
||||
@@ -10,8 +10,11 @@ vars {
|
||||
rating: 5
|
||||
is_visible: true
|
||||
library_folder: /app/uploads
|
||||
opds_base_url:
|
||||
}
|
||||
vars:secret [
|
||||
token,
|
||||
refresh_token
|
||||
refresh_token,
|
||||
kobo_device_token,
|
||||
other_device_id
|
||||
]
|
||||
Reference in New Issue
Block a user