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>
16 KiB
OAuth Troubleshooting
This guide covers OAuth-specific issues and solutions for the Nextcloud MCP server.
For general troubleshooting, see Troubleshooting Guide.
Quick Diagnosis
Start here to identify your issue:
| Symptom | Likely Cause | Quick Fix Link |
|---|---|---|
| "OAuth mode requires NEXTCLOUD_HOST" | Missing environment variable | Missing NEXTCLOUD_HOST |
| "OAuth mode requires client credentials OR dynamic registration" | OIDC apps not configured | Missing OIDC Apps |
| "PKCE support validation failed" | OIDC app doesn't advertise PKCE | PKCE Not Advertised |
| "Stored client has expired" | Dynamic client expired | Client Expired |
| Only seeing Notes tools (7 instead of 90+) | Limited OAuth scopes granted | Limited Scopes |
| HTTP 401 for Notes API | Bearer token patch missing | Bearer Token Auth Fails |
| "OIDC discovery failed" | Network or configuration issue | Discovery Failed |
| "Database error" on OAuth client storage | Database permissions issue | Database Permission Error |
Configuration Issues
Missing NEXTCLOUD_HOST
Error Message:
OAuth mode requires NEXTCLOUD_HOST environment variable
Cause: The NEXTCLOUD_HOST environment variable is not set or empty.
Solution:
-
Add to your
.envfile:NEXTCLOUD_HOST=https://your.nextcloud.instance.com -
Reload environment variables:
export $(grep -v '^#' .env | xargs) -
Verify it's set:
echo $NEXTCLOUD_HOST # Should output: https://your.nextcloud.instance.com
Missing or Misconfigured OIDC Apps
Error Message:
OAuth mode requires either client credentials OR dynamic client registration
Cause: The required Nextcloud OIDC apps are either:
- Not installed
- Not enabled
- Missing configuration
Solution:
Step 1: Verify both apps are installed:
# Check installed apps
php occ app:list | grep -E "oidc|user_oidc"
# Should show:
# - oidc: enabled
# - user_oidc: enabled
If not installed:
- Open Nextcloud as administrator
- Navigate to Apps → Security
- Install "OIDC" (OIDC Identity Provider)
- Install "OpenID Connect user backend" (user_oidc)
- Enable both apps
Step 2: Enable dynamic client registration:
- Go to Settings → OIDC (Administration)
- Enable "Allow dynamic client registration"
Step 3: Configure Bearer token validation:
php occ config:system:set user_oidc oidc_provider_bearer_validation --value=true --type=boolean
Step 4: Verify discovery endpoint:
curl https://your.nextcloud.instance.com/.well-known/openid-configuration | jq '.registration_endpoint'
# Should output:
# "https://your.nextcloud.instance.com/apps/oidc/register"
Alternative: Use pre-configured client credentials:
# Register client via CLI
php occ oidc:create \
--name="Nextcloud MCP Server" \
--type=confidential \
--redirect-uri="http://localhost:8000/oauth/callback"
# Add to .env
echo "NEXTCLOUD_OIDC_CLIENT_ID=<client-id>" >> .env
echo "NEXTCLOUD_OIDC_CLIENT_SECRET=<client-secret>" >> .env
Client Expired
Error Message:
Stored client has expired
Cause: Dynamically registered OAuth clients expire (default: 1 hour).
Solution:
Option 1: Restart the Server (Automatic re-registration)
uv run nextcloud-mcp-server --oauth
# Server automatically re-registers if credentials expired
Option 2: Use Pre-configured Credentials (Recommended for production)
# Register permanent client via Nextcloud CLI
php occ oidc:create \
--name="Nextcloud MCP Server" \
--type=confidential \
--redirect-uri="http://localhost:8000/oauth/callback"
# Add to .env
NEXTCLOUD_OIDC_CLIENT_ID=<from-output>
NEXTCLOUD_OIDC_CLIENT_SECRET=<from-output>
Pre-configured clients don't expire.
Option 3: Increase Expiration Time
# Via Nextcloud CLI (default: 3600 seconds = 1 hour)
php occ config:app:set oidc expire_time --value "86400" # 24 hours
Database Permission Error
Error Message:
Permission denied when accessing SQLite database
Database is locked
Cause: The server cannot access the SQLite database file.
Solution:
# Check database directory permissions
ls -la /app/data/
# Ensure directory is writable
chmod 755 /app/data
# Check if database file exists and has correct permissions
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 Docker deployments: Ensure the data directory is properly mounted as a volume:
volumes:
- ./data:/app/data # Persistent storage for SQLite database
Discovery and Connection Issues
OIDC Discovery Failed
Error Message:
OIDC discovery failed
Cannot reach OIDC discovery endpoint
Cause: The server cannot reach the Nextcloud OIDC discovery endpoint.
Solution:
Step 1: Verify Nextcloud URL is correct:
echo $NEXTCLOUD_HOST
# Should be full URL: https://your.nextcloud.instance.com
Step 2: Test discovery endpoint manually:
curl https://your.nextcloud.instance.com/.well-known/openid-configuration
# Should return JSON with OIDC configuration
# {
# "issuer": "https://your.nextcloud.instance.com",
# "authorization_endpoint": "https://your.nextcloud.instance.com/apps/oidc/authorize",
# ...
# }
Step 3: Check network connectivity:
# Test basic connectivity
ping your.nextcloud.instance.com
# Test HTTPS
curl -I https://your.nextcloud.instance.com
Step 4: Verify both OIDC apps are enabled:
php occ app:list | grep -E "oidc|user_oidc"
Step 5: Check firewall rules (if using Docker):
# Check if MCP server can reach Nextcloud
docker exec nextcloud-mcp-server curl https://your.nextcloud.instance.com/.well-known/openid-configuration
Authentication Issues
Bearer Token Authentication Fails
Error Message:
HTTP 401 Unauthorized when calling Nextcloud APIs
Symptoms:
- OCS APIs work (
/ocs/v2.php/cloud/capabilities) - App APIs fail (
/apps/notes/api/,/apps/calendar/, etc.)
Cause: The user_oidc app's CORS middleware interferes with Bearer token authentication for non-OCS endpoints.
Solution: Apply the Bearer token patch to user_oidc app.
See Upstream Status for details.
Quick Patch:
# SSH into Nextcloud server
cd /path/to/nextcloud/apps/user_oidc
# Edit lib/User/Backend.php
# Add this line before each return statement in getCurrentUserId() method:
$this->session->set('app_api', true);
# Lines to modify: ~243, ~310, ~315, ~337
Test the fix:
# Get an OAuth token (from MCP client or test)
TOKEN="your_access_token"
# Test Notes API
curl -H "Authorization: Bearer $TOKEN" \
https://your.nextcloud.instance.com/apps/notes/api/v1/notes
# Should return notes JSON (not 401)
PKCE Not Advertised
Error Message:
ERROR: OIDC CONFIGURATION ERROR - Missing PKCE Support Advertisement
⚠️ MCP clients (like Claude Code) WILL REJECT this provider!
Cause: The OIDC discovery endpoint doesn't include code_challenge_methods_supported field.
Impact:
- Some MCP clients may refuse to connect
- Standards compliance issue (RFC 8414)
- Functionality still works (PKCE is accepted, just not advertised)
Solution:
Short-term: The MCP server logs a warning but continues. OAuth flow still works.
Long-term: Update the oidc app to advertise PKCE support.
See Upstream Status for tracking.
Verify:
curl https://your.nextcloud.instance.com/.well-known/openid-configuration | jq '.code_challenge_methods_supported'
# Should return:
# ["S256", "plain"]
# If null, PKCE isn't advertised (but still works)
Runtime Issues
MCP Client Can't Authenticate
Symptoms:
- Client connects but OAuth flow fails
- Authorization redirects don't work
- Token exchange fails
Diagnosis:
Step 1: Verify OAuth is configured correctly:
uv run nextcloud-mcp-server --oauth --log-level debug
Look for:
INFO OAuth initialization complete
INFO MCP server ready at http://127.0.0.1:8000
Step 2: Check OIDC discovery:
curl https://your.nextcloud.instance.com/.well-known/openid-configuration
Step 3: Verify MCP server URL matches client expectations:
echo $NEXTCLOUD_MCP_SERVER_URL
# Should match the URL clients use to connect
# Default: http://localhost:8000
If MCP server is on a different host/port, update:
NEXTCLOUD_MCP_SERVER_URL=http://actual-host:actual-port
Step 4: Check redirect URI configuration:
For pre-configured clients, ensure redirect URI matches:
# Client redirect URI should be:
http://your-mcp-server-url/oauth/callback
# Example for local server:
http://localhost:8000/oauth/callback
Tools Return 401 Errors
Symptoms:
- OAuth flow completes successfully
- Token is valid
- MCP tools return 401 errors
Cause: Bearer token not working with Nextcloud APIs.
Solution: See Bearer Token Authentication Fails above.
Limited Scopes - Only Seeing Notes Tools
Symptoms:
- MCP client (e.g., Claude Code) successfully connects via OAuth
- Only Notes tools are available (7 tools instead of 90+)
- Token scopes show only
mcp:notes:readandmcp:notes:write
Cause: During the OAuth consent flow, the user only granted access to Notes scopes, or the client only requested those scopes.
Diagnosis:
Check what scopes the client has been granted:
# View registered clients and their allowed scopes
php occ oidc:list | jq '.[] | select(.name | contains("Claude Code")) | {name, allowed_scopes}'
Look for the client's allowed_scopes field. If it's empty or only contains notes scopes, that's the issue.
Solution:
Option 1: Delete Client and Reconnect (Recommended for MCP clients)
# Find the client ID
php occ oidc:list | jq '.[] | select(.name | contains("Claude Code")) | {name, client_id}'
# Delete the client
php occ oidc:delete <client_id>
# Reconnect from Claude Code
# This will trigger a new OAuth flow where you can grant all scopes
When reconnecting, you'll see a consent screen listing all available scopes. Make sure to approve all the scopes you want the client to access.
Option 2: Update Client Scopes via CLI
# Update allowed scopes for an existing client
php occ oidc:update <client_id> \
--allowed-scopes "openid profile email mcp:notes:read mcp:notes:write mcp:calendar:read mcp:calendar:write mcp:contacts:read mcp:contacts:write mcp:cookbook:read mcp:cookbook:write mcp:deck:read mcp:deck:write mcp:tables:read mcp:tables:write mcp:files:read mcp:files:write mcp:sharing:read mcp:sharing:write"
# User will need to reconnect to get new token with updated scopes
Verify Available Scopes:
Check what scopes the MCP server advertises:
curl http://localhost:8001/.well-known/oauth-protected-resource | jq '.scopes_supported'
# Should show all 16 scope categories:
# - openid
# - mcp:notes:read, mcp:notes:write
# - mcp:calendar:read, mcp:calendar:write
# - mcp:contacts:read, mcp:contacts:write
# - mcp:cookbook:read, mcp:cookbook:write
# - mcp:deck:read, mcp:deck:write
# - mcp:tables:read, mcp:tables:write
# - mcp:files:read, mcp:files:write
# - mcp:sharing:read, mcp:sharing:write
Understanding Scope Filtering:
The MCP server dynamically filters tools based on the scopes in your access token:
- Check server logs for:
✂️ JWT scope filtering: X/90 tools available for scopes: {...} - This shows how many tools are visible vs total available
- Each tool requires specific scopes (read and/or write)
Available Scope Categories:
| Scope Prefix | Nextcloud App | Read Operations | Write Operations |
|---|---|---|---|
mcp:notes:* |
Notes | Get, search, list | Create, update, delete, append |
mcp:calendar:* |
Calendar (CalDAV) | Get events, todos, calendars | Create/update/delete events, todos |
mcp:contacts:* |
Contacts (CardDAV) | Get contacts, address books | Create/update/delete contacts |
mcp:cookbook:* |
Cookbook | Get recipes, search | Create/update recipes |
mcp:deck:* |
Deck | Get boards, cards | Create/update boards, cards |
mcp:tables:* |
Tables | Get rows, tables | Create/update/delete rows |
mcp:files:* |
Files (WebDAV) | List, read files | Upload, delete, move files |
mcp:sharing:* |
Sharing | Get shares | Create/update shares |
Switching Authentication Modes
From BasicAuth to OAuth
# 1. Remove or comment out USERNAME/PASSWORD in .env
sed -i 's/^NEXTCLOUD_USERNAME/#NEXTCLOUD_USERNAME/' .env
sed -i 's/^NEXTCLOUD_PASSWORD/#NEXTCLOUD_PASSWORD/' .env
# 2. Ensure NEXTCLOUD_HOST is set
grep NEXTCLOUD_HOST .env
# 3. Restart server with OAuth
export $(grep -v '^#' .env | xargs)
uv run nextcloud-mcp-server --oauth
From OAuth to BasicAuth
# 1. Add USERNAME/PASSWORD to .env
echo "NEXTCLOUD_USERNAME=your-username" >> .env
echo "NEXTCLOUD_PASSWORD=your-password" >> .env
# 2. Restart server (BasicAuth auto-detected)
export $(grep -v '^#' .env | xargs)
uv run nextcloud-mcp-server --no-oauth
Advanced Debugging
Enable Debug Logging
uv run nextcloud-mcp-server --oauth --log-level debug
Look for:
- OIDC discovery details
- Client registration attempts
- Token validation logs
- API request/response details
Test Discovery Endpoint
# Full discovery response
curl https://your.nextcloud.instance.com/.well-known/openid-configuration | jq
# Check specific fields
curl https://your.nextcloud.instance.com/.well-known/openid-configuration | jq '{
issuer,
authorization_endpoint,
token_endpoint,
userinfo_endpoint,
registration_endpoint,
code_challenge_methods_supported
}'
Test Token Validation
# Get userinfo with token
curl -H "Authorization: Bearer $TOKEN" \
https://your.nextcloud.instance.com/apps/oidc/userinfo
# Should return user info:
# {
# "sub": "username",
# "preferred_username": "username",
# "name": "Display Name",
# ...
# }
Test Nextcloud API Access
# Test OCS API (should work)
curl -H "Authorization: Bearer $TOKEN" \
"$NEXTCLOUD_HOST/ocs/v2.php/cloud/capabilities?format=json" \
-H "OCS-APIRequest: true"
# Test app API (requires patch)
curl -H "Authorization: Bearer $TOKEN" \
"$NEXTCLOUD_HOST/apps/notes/api/v1/notes"
Getting Help
If you continue to experience issues:
1. Collect Diagnostic Information
# Server version
uv run nextcloud-mcp-server --version
# Python version
python3 --version
# Server logs with debug
uv run nextcloud-mcp-server --oauth --log-level debug 2>&1 | tee mcp-server.log
# OIDC discovery
curl https://your.nextcloud.instance.com/.well-known/openid-configuration > oidc-discovery.json
# Nextcloud version
# Check in Nextcloud admin panel or:
php occ -V
2. Check Documentation
- OAuth Architecture - How OAuth works
- OAuth Setup Guide - Configuration steps
- Upstream Status - Required patches
- Configuration - Environment variables
3. Open an Issue
If problems persist, open an issue with:
- Error messages (full text)
- Server logs (with
--log-level debug) - OIDC discovery response (from curl command above)
- Nextcloud version
- OIDC app versions (
oidcanduser_oidc) - Steps to reproduce
- Environment details (OS, Python version, Docker vs local)
See Also
- OAuth Quick Start - Get started quickly
- OAuth Setup Guide - Detailed configuration
- OAuth Architecture - Technical details
- Upstream Status - Required patches
- General Troubleshooting - Non-OAuth issues