docs: Replace .nextcloud_oauth_client.json references with SQLite storage

Replace all references to the JSON file-based OAuth client storage with
SQLite database storage in documentation. OAuth client credentials are now
stored in the SQLite database instead of .nextcloud_oauth_client.json.

Changes:
- Update oauth-architecture.md to reference SQLite database
- Update jwt-oauth-reference.md credential storage sections
- Update oauth-setup.md Docker volume mounts and security best practices
- Update oauth-troubleshooting.md file permission → database permission errors
- Update configuration.md to remove JSON file chmod instructions
- Update troubleshooting.md database permission troubleshooting

The code already uses SQLite (RefreshTokenStorage class), so only
documentation needed updating.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2025-11-02 19:06:59 +01:00
parent 4c7d1cfc8d
commit 2ca6725fc6
6 changed files with 53 additions and 66 deletions
+2 -11
View File
@@ -45,8 +45,7 @@ NEXTCLOUD_HOST=https://your.nextcloud.instance.com
NEXTCLOUD_OIDC_CLIENT_ID=your-client-id NEXTCLOUD_OIDC_CLIENT_ID=your-client-id
NEXTCLOUD_OIDC_CLIENT_SECRET=your-client-secret NEXTCLOUD_OIDC_CLIENT_SECRET=your-client-secret
# OAuth Storage and Callback Settings (optional) # OAuth Callback Settings (optional)
NEXTCLOUD_OIDC_CLIENT_STORAGE=.nextcloud_oauth_client.json
NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000 NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
# Leave these EMPTY for OAuth mode # Leave these EMPTY for OAuth mode
@@ -61,7 +60,6 @@ NEXTCLOUD_PASSWORD=
| `NEXTCLOUD_HOST` | ✅ Yes | - | Full URL of your Nextcloud instance (e.g., `https://cloud.example.com`) | | `NEXTCLOUD_HOST` | ✅ Yes | - | Full URL of your Nextcloud instance (e.g., `https://cloud.example.com`) |
| `NEXTCLOUD_OIDC_CLIENT_ID` | ⚠️ Optional | - | OAuth client ID (auto-registers if empty) | | `NEXTCLOUD_OIDC_CLIENT_ID` | ⚠️ Optional | - | OAuth client ID (auto-registers if empty) |
| `NEXTCLOUD_OIDC_CLIENT_SECRET` | ⚠️ Optional | - | OAuth client secret (auto-registers if empty) | | `NEXTCLOUD_OIDC_CLIENT_SECRET` | ⚠️ Optional | - | OAuth client secret (auto-registers if empty) |
| `NEXTCLOUD_OIDC_CLIENT_STORAGE` | ⚠️ Optional | `.nextcloud_oauth_client.json` | Path to store auto-registered client credentials |
| `NEXTCLOUD_MCP_SERVER_URL` | ⚠️ Optional | `http://localhost:8000` | MCP server URL for OAuth callbacks | | `NEXTCLOUD_MCP_SERVER_URL` | ⚠️ Optional | `http://localhost:8000` | MCP server URL for OAuth callbacks |
| `NEXTCLOUD_USERNAME` | ❌ Must be empty | - | Leave empty to enable OAuth mode | | `NEXTCLOUD_USERNAME` | ❌ Must be empty | - | Leave empty to enable OAuth mode |
| `NEXTCLOUD_PASSWORD` | ❌ Must be empty | - | Leave empty to enable OAuth mode | | `NEXTCLOUD_PASSWORD` | ❌ Must be empty | - | Leave empty to enable OAuth mode |
@@ -160,10 +158,6 @@ Options:
NEXTCLOUD_OIDC_CLIENT_ID env var) NEXTCLOUD_OIDC_CLIENT_ID env var)
--oauth-client-secret TEXT OAuth client secret (can also use --oauth-client-secret TEXT OAuth client secret (can also use
NEXTCLOUD_OIDC_CLIENT_SECRET env var) NEXTCLOUD_OIDC_CLIENT_SECRET env var)
--oauth-storage-path TEXT Path to store OAuth client credentials
(can also use
NEXTCLOUD_OIDC_CLIENT_STORAGE env var)
[default: .nextcloud_oauth_client.json]
--mcp-server-url TEXT MCP server URL for OAuth callbacks (can --mcp-server-url TEXT MCP server URL for OAuth callbacks (can
also use NEXTCLOUD_MCP_SERVER_URL env also use NEXTCLOUD_MCP_SERVER_URL env
var) [default: http://localhost:8000] var) [default: http://localhost:8000]
@@ -225,10 +219,7 @@ uv run nextcloud-mcp-server --no-oauth \
- Store OAuth client credentials securely - Store OAuth client credentials securely
- Use environment variables from your deployment platform (Docker secrets, Kubernetes ConfigMaps, etc.) - Use environment variables from your deployment platform (Docker secrets, Kubernetes ConfigMaps, etc.)
- Never commit credentials to version control - Never commit credentials to version control
- Set appropriate file permissions on credential storage: - SQLite database permissions are handled automatically by the server
```bash
chmod 600 .nextcloud_oauth_client.json
```
### For Docker ### For Docker
+10 -11
View File
@@ -272,7 +272,7 @@ mcp-oauth:
**Key Points:** **Key Points:**
- **No credentials needed** - DCR automatically registers the client on first start - **No credentials needed** - DCR automatically registers the client on first start
- **Credentials persist** - Saved to `.nextcloud_oauth_client.json` and reused - **Credentials persist** - Saved to SQLite database and reused
- **JWT tokens** - Use `--oauth-token-type jwt` for better performance - **JWT tokens** - Use `--oauth-token-type jwt` for better performance
- **Token verifier supports both** - Can handle JWT and opaque tokens - **Token verifier supports both** - Can handle JWT and opaque tokens
- **Pre-configured credentials** - Providing `CLIENT_ID`/`CLIENT_SECRET` skips DCR - **Pre-configured credentials** - Providing `CLIENT_ID`/`CLIENT_SECRET` skips DCR
@@ -286,7 +286,6 @@ mcp-oauth:
| `NEXTCLOUD_PUBLIC_ISSUER_URL` | Public issuer URL for JWT validation | (uses `NEXTCLOUD_HOST`) | | `NEXTCLOUD_PUBLIC_ISSUER_URL` | Public issuer URL for JWT validation | (uses `NEXTCLOUD_HOST`) |
| `NEXTCLOUD_OIDC_CLIENT_ID` | Pre-configured OAuth client ID | (optional - uses DCR if unset) | | `NEXTCLOUD_OIDC_CLIENT_ID` | Pre-configured OAuth client ID | (optional - uses DCR if unset) |
| `NEXTCLOUD_OIDC_CLIENT_SECRET` | Pre-configured OAuth client secret | (optional - uses DCR if unset) | | `NEXTCLOUD_OIDC_CLIENT_SECRET` | Pre-configured OAuth client secret | (optional - uses DCR if unset) |
| `NEXTCLOUD_OIDC_CLIENT_STORAGE` | Path to persist DCR-registered credentials | `.nextcloud_oauth_client.json` |
| `NEXTCLOUD_OIDC_SCOPES` | Space-separated scopes to request | `"openid profile email mcp:notes:read mcp:notes:write"` | | `NEXTCLOUD_OIDC_SCOPES` | Space-separated scopes to request | `"openid profile email mcp:notes:read mcp:notes:write"` |
| `NEXTCLOUD_OIDC_TOKEN_TYPE` | Token format: `"jwt"` or `"Bearer"` | `"Bearer"` | | `NEXTCLOUD_OIDC_TOKEN_TYPE` | Token format: `"jwt"` or `"Bearer"` | `"Bearer"` |
@@ -303,8 +302,8 @@ When the MCP server starts in OAuth mode, it follows this **three-tier credentia
├─ NEXTCLOUD_OIDC_CLIENT_ID ├─ NEXTCLOUD_OIDC_CLIENT_ID
└─ NEXTCLOUD_OIDC_CLIENT_SECRET └─ NEXTCLOUD_OIDC_CLIENT_SECRET
2. Storage File (Second Priority) 2. SQLite Database (Second Priority)
└─ NEXTCLOUD_OIDC_CLIENT_STORAGE (.nextcloud_oauth_client.json) └─ OAuth client credentials table
3. Dynamic Client Registration (Automatic Fallback) 3. Dynamic Client Registration (Automatic Fallback)
├─ Discovers registration endpoint from /.well-known/openid-configuration ├─ Discovers registration endpoint from /.well-known/openid-configuration
@@ -327,10 +326,10 @@ export NEXTCLOUD_OIDC_TOKEN_TYPE=jwt # or "Bearer" for opaque tokens
**Credential Storage:** **Credential Storage:**
- Registered credentials are saved to `NEXTCLOUD_OIDC_CLIENT_STORAGE` (default: `.nextcloud_oauth_client.json`) - Registered credentials are saved to SQLite database
- File has restrictive permissions (0600 - owner read/write only) - Database is encrypted and protected by file system permissions
- Credentials are reused on subsequent starts (no re-registration needed) - Credentials are reused on subsequent starts (no re-registration needed)
- Storage file is checked for expiration (auto-regenerates if expired) - Stored credentials are checked for expiration (auto-regenerates if expired)
**Format:** **Format:**
```json ```json
@@ -386,9 +385,9 @@ export NEXTCLOUD_OIDC_CLIENT_ID="<client_id>"
export NEXTCLOUD_OIDC_CLIENT_SECRET="<client_secret>" export NEXTCLOUD_OIDC_CLIENT_SECRET="<client_secret>"
export NEXTCLOUD_OIDC_TOKEN_TYPE="jwt" export NEXTCLOUD_OIDC_TOKEN_TYPE="jwt"
# Option 2: Storage file (second priority) # Option 2: SQLite database (second priority)
# Save the JSON response to .nextcloud_oauth_client.json # Credentials are automatically saved to the database after DCR
# Server will automatically load it on startup # Server will automatically load them on startup
``` ```
When credentials are provided via environment variables or storage file, **DCR is skipped**. When credentials are provided via environment variables or storage file, **DCR is skipped**.
@@ -724,7 +723,7 @@ docker compose exec db mariadb -u nextcloud -ppassword nextcloud \
1. Ensure `NEXTCLOUD_OIDC_SCOPES` environment variable is set correctly 1. Ensure `NEXTCLOUD_OIDC_SCOPES` environment variable is set correctly
2. Check MCP server startup logs for the scopes being requested 2. Check MCP server startup logs for the scopes being requested
3. Verify DCR is enabled in Nextcloud OIDC app settings 3. Verify DCR is enabled in Nextcloud OIDC app settings
4. Delete `.nextcloud_oauth_client.json` and restart to force re-registration 4. Clear the SQLite database OAuth client entry and restart to force re-registration
### Issue: Token Type Case Sensitivity ### Issue: Token Type Case Sensitivity
+4 -5
View File
@@ -39,7 +39,7 @@ Phase 0: MCP Server Startup & Client Registration (DCR - RFC 7591)
│ 0d. Client credentials │ │ 0d. Client credentials │
│<────────────────────────────────────┤ │<────────────────────────────────────┤
│ {client_id, client_secret} │ │ {client_id, client_secret} │
│ → Saved to .nextcloud_oauth_*.json │ → Saved to SQLite database
│ │ │ │
│ ✓ Server ready for connections │ │ ✓ Server ready for connections │
@@ -211,7 +211,7 @@ Insufficient Scope Example (Step-Up Authorization)
- **PKCE Validation**: Verifies server advertises S256 code challenge method - **PKCE Validation**: Verifies server advertises S256 code challenge method
- **Dynamic Client Registration (DCR)**: Automatically registers OAuth client via `/apps/oidc/register` (RFC 7591) - **Dynamic Client Registration (DCR)**: Automatically registers OAuth client via `/apps/oidc/register` (RFC 7591)
- Or loads pre-configured client credentials - Or loads pre-configured client credentials
- Saves credentials to `.nextcloud_oauth_client.json` - Saves credentials to SQLite database
- **Tool Registration**: Loads all MCP tools with their `@require_scopes` decorators - **Tool Registration**: Loads all MCP tools with their `@require_scopes` decorators
#### Client Connection Phase #### Client Connection Phase
@@ -324,7 +324,7 @@ The OAuth flow consists of four distinct phases (see diagram above for visual re
- MCP server registers itself as OAuth client (RFC 7591) - MCP server registers itself as OAuth client (RFC 7591)
- Provides: client name, redirect URIs, requested scopes, token type - Provides: client name, redirect URIs, requested scopes, token type
- Receives: `client_id`, `client_secret` - Receives: `client_id`, `client_secret`
- Saves credentials to `.nextcloud_oauth_client.json` - Saves credentials to SQLite database
3. **Tool Registration** 3. **Tool Registration**
- All MCP tools loaded with their `@require_scopes` decorators - All MCP tools loaded with their `@require_scopes` decorators
@@ -515,7 +515,7 @@ NEXTCLOUD_HOST=https://nextcloud.example.com
**How it works**: **How it works**:
1. Server checks `/.well-known/openid-configuration` for `registration_endpoint` 1. Server checks `/.well-known/openid-configuration` for `registration_endpoint`
2. Calls `/apps/oidc/register` to register a client on first startup 2. Calls `/apps/oidc/register` to register a client on first startup
3. Saves credentials to `.nextcloud_oauth_client.json` 3. Saves credentials to SQLite database
4. Reuses these credentials on subsequent startups 4. Reuses these credentials on subsequent startups
5. Re-registers only if credentials are missing or expired 5. Re-registers only if credentials are missing or expired
@@ -718,7 +718,6 @@ See [Configuration Guide](configuration.md) for all OAuth environment variables:
| `NEXTCLOUD_OIDC_CLIENT_ID` | Pre-configured client ID (optional) | | `NEXTCLOUD_OIDC_CLIENT_ID` | Pre-configured client ID (optional) |
| `NEXTCLOUD_OIDC_CLIENT_SECRET` | Pre-configured client secret (optional) | | `NEXTCLOUD_OIDC_CLIENT_SECRET` | Pre-configured client secret (optional) |
| `NEXTCLOUD_MCP_SERVER_URL` | MCP server URL for OAuth callbacks | | `NEXTCLOUD_MCP_SERVER_URL` | MCP server URL for OAuth callbacks |
| `NEXTCLOUD_OIDC_CLIENT_STORAGE` | Path for auto-registered credentials |
## Testing ## Testing
+5 -9
View File
@@ -170,7 +170,7 @@ You have two options for managing OAuth clients:
**How it works**: **How it works**:
- MCP server automatically registers an OAuth client on first startup - MCP server automatically registers an OAuth client on first startup
- Uses Nextcloud's dynamic client registration endpoint - Uses Nextcloud's dynamic client registration endpoint
- Saves credentials to `.nextcloud_oauth_client.json` - Saves credentials to SQLite database
- Reuses stored credentials on subsequent restarts - Reuses stored credentials on subsequent restarts
- Re-registers automatically if credentials expire - Re-registers automatically if credentials expire
@@ -253,9 +253,6 @@ NEXTCLOUD_PASSWORD=
# Optional: MCP server URL (for OAuth callbacks) # Optional: MCP server URL (for OAuth callbacks)
NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000 NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
# Optional: Client storage path
NEXTCLOUD_OIDC_CLIENT_STORAGE=.nextcloud_oauth_client.json
EOF EOF
``` ```
@@ -291,7 +288,6 @@ EOF
| `NEXTCLOUD_OIDC_CLIENT_ID` | ⚠️ Mode B only | - | OAuth client ID | | `NEXTCLOUD_OIDC_CLIENT_ID` | ⚠️ Mode B only | - | OAuth client ID |
| `NEXTCLOUD_OIDC_CLIENT_SECRET` | ⚠️ Mode B only | - | OAuth client secret | | `NEXTCLOUD_OIDC_CLIENT_SECRET` | ⚠️ Mode B only | - | OAuth client secret |
| `NEXTCLOUD_MCP_SERVER_URL` | ⚠️ Optional | `http://localhost:8000` | MCP server URL for callbacks | | `NEXTCLOUD_MCP_SERVER_URL` | ⚠️ Optional | `http://localhost:8000` | MCP server URL for callbacks |
| `NEXTCLOUD_OIDC_CLIENT_STORAGE` | ⚠️ Optional | `.nextcloud_oauth_client.json` | Client credentials storage path |
| `NEXTCLOUD_USERNAME` | ❌ Must be empty | - | Leave empty for OAuth | | `NEXTCLOUD_USERNAME` | ❌ Must be empty | - | Leave empty for OAuth |
| `NEXTCLOUD_PASSWORD` | ❌ Must be empty | - | Leave empty for OAuth | | `NEXTCLOUD_PASSWORD` | ❌ Must be empty | - | Leave empty for OAuth |
@@ -334,7 +330,7 @@ INFO OIDC discovery successful
INFO Attempting dynamic client registration... INFO Attempting dynamic client registration...
INFO Dynamic client registration successful INFO Dynamic client registration successful
INFO OAuth client ready: <client-id>... INFO OAuth client ready: <client-id>...
INFO Saved OAuth client credentials to .nextcloud_oauth_client.json INFO Saved OAuth client credentials to SQLite database
INFO OAuth initialization complete INFO OAuth initialization complete
INFO MCP server ready at http://127.0.0.1:8000 INFO MCP server ready at http://127.0.0.1:8000
``` ```
@@ -427,9 +423,9 @@ uv run nextcloud-mcp-server --oauth --log-level debug
2. **Secure Credential Storage** 2. **Secure Credential Storage**
```bash ```bash
# Set restrictive permissions # Set restrictive permissions on environment file
chmod 600 .nextcloud_oauth_client.json
chmod 600 .env chmod 600 .env
# Database permissions are handled automatically
``` ```
3. **Use HTTPS for MCP Server** 3. **Use HTTPS for MCP Server**
@@ -474,7 +470,7 @@ services:
NEXTCLOUD_OIDC_CLIENT_SECRET: ${NEXTCLOUD_OIDC_CLIENT_SECRET} NEXTCLOUD_OIDC_CLIENT_SECRET: ${NEXTCLOUD_OIDC_CLIENT_SECRET}
NEXTCLOUD_MCP_SERVER_URL: http://your-server:8000 NEXTCLOUD_MCP_SERVER_URL: http://your-server:8000
volumes: volumes:
- ./oauth_client.json:/app/.nextcloud_oauth_client.json - ./data:/app/data # For SQLite database persistence
command: ["--oauth", "--transport", "streamable-http"] command: ["--oauth", "--transport", "streamable-http"]
restart: unless-stopped restart: unless-stopped
``` ```
+19 -20
View File
@@ -17,7 +17,7 @@ Start here to identify your issue:
| Only seeing Notes tools (7 instead of 90+) | Limited OAuth scopes granted | [Limited Scopes](#limited-scopes---only-seeing-notes-tools) | | Only seeing Notes tools (7 instead of 90+) | Limited OAuth scopes granted | [Limited Scopes](#limited-scopes---only-seeing-notes-tools) |
| HTTP 401 for Notes API | Bearer token patch missing | [Bearer Token Auth Fails](#bearer-token-authentication-fails) | | HTTP 401 for Notes API | Bearer token patch missing | [Bearer Token Auth Fails](#bearer-token-authentication-fails) |
| "OIDC discovery failed" | Network or configuration issue | [Discovery Failed](#oidc-discovery-failed) | | "OIDC discovery failed" | Network or configuration issue | [Discovery Failed](#oidc-discovery-failed) |
| "Permission denied" on .nextcloud_oauth_client.json | File permissions issue | [File Permission Error](#file-permission-error) | | "Database error" on OAuth client storage | Database permissions issue | [Database Permission Error](#database-permission-error) |
## Configuration Issues ## Configuration Issues
@@ -161,39 +161,38 @@ php occ config:app:set oidc expire_time --value "86400" # 24 hours
--- ---
### File Permission Error ### Database Permission Error
**Error Message**: **Error Message**:
``` ```
Permission denied when reading/writing .nextcloud_oauth_client.json Permission denied when accessing SQLite database
Database is locked
``` ```
**Cause**: The server cannot access the OAuth client storage file. **Cause**: The server cannot access the SQLite database file.
**Solution**: **Solution**:
```bash ```bash
# Check file permissions # Check database directory permissions
ls -la .nextcloud_oauth_client.json ls -la /app/data/
# Fix file permissions (owner read/write only)
chmod 600 .nextcloud_oauth_client.json
# Ensure directory is writable # Ensure directory is writable
chmod 755 $(dirname .nextcloud_oauth_client.json) chmod 755 /app/data
# If file doesn't exist, ensure directory is writable # Check if database file exists and has correct permissions
mkdir -p $(dirname .nextcloud_oauth_client.json) ls -la /app/data/tokens.db
chmod 644 /app/data/tokens.db
# If running in Docker, ensure volume is mounted correctly
docker compose logs mcp-oauth | grep -i "database\|sqlite"
``` ```
For custom storage paths: **For Docker deployments**:
```bash Ensure the data directory is properly mounted as a volume:
# Set custom path in .env ```yaml
NEXTCLOUD_OIDC_CLIENT_STORAGE=/path/to/custom/oauth_client.json volumes:
- ./data:/app/data # Persistent storage for SQLite database
# Ensure directory exists and is writable
mkdir -p $(dirname /path/to/custom/oauth_client.json)
chmod 755 $(dirname /path/to/custom/oauth_client.json)
``` ```
--- ---
+13 -10
View File
@@ -136,24 +136,27 @@ A patch for the `user_oidc` app is required to fix Bearer token support. See [oa
--- ---
### Issue: "Permission denied" when reading/writing OAuth client credentials file ### Issue: "Permission denied" or "Database is locked" when accessing OAuth client storage
**Cause:** The server cannot access the OAuth client storage file (default: `.nextcloud_oauth_client.json`). **Cause:** The server cannot access the SQLite database for OAuth client credentials storage.
**Solution:** **Solution:**
```bash ```bash
# Check file permissions # Check database directory permissions
ls -la .nextcloud_oauth_client.json ls -la data/
# Fix file permissions (should be 0600 - owner read/write only) # Ensure directory is writable
chmod 600 .nextcloud_oauth_client.json chmod 755 data/
# Ensure the directory is writable # Check if database file exists and has correct permissions
chmod 755 $(dirname .nextcloud_oauth_client.json) ls -la data/tokens.db
chmod 644 data/tokens.db
# If the file doesn't exist, ensure the directory is writable so it can be created # For Docker deployments, ensure volume is mounted correctly:
mkdir -p $(dirname .nextcloud_oauth_client.json) # docker-compose.yml should have:
# volumes:
# - ./data:/app/data
``` ```
--- ---