Files
nextcloud-mcp-server/docs/oauth-troubleshooting.md
Chris Coutinho 2ca6725fc6 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>
2025-11-02 22:03:21 +01:00

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:

  1. Add to your .env file:

    NEXTCLOUD_HOST=https://your.nextcloud.instance.com
    
  2. Reload environment variables:

    export $(grep -v '^#' .env | xargs)
    
  3. 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:

  1. Open Nextcloud as administrator
  2. Navigate to AppsSecurity
  3. Install "OIDC" (OIDC Identity Provider)
  4. Install "OpenID Connect user backend" (user_oidc)
  5. Enable both apps

Step 2: Enable dynamic client registration:

  1. Go to SettingsOIDC (Administration)
  2. 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:read and mcp: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

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 (oidc and user_oidc)
  • Steps to reproduce
  • Environment details (OS, Python version, Docker vs local)

See Also