This guide walks you through setting up OAuth2/OIDC authentication for the Nextcloud MCP server in production.
Quick Start? If you want a 5-minute setup for development, see OAuth Quick Start.
- Prerequisites
- Architecture Overview
- Step 1: Install Nextcloud Apps
- Step 2: Configure OIDC Apps
- Step 3: Choose Deployment Mode
- Step 4: Configure MCP Server
- Step 5: Start and Verify
- Testing Authentication
- Production Recommendations
Before beginning, ensure you have:
- Nextcloud instance with administrator access
- Nextcloud version 28 or later
- SSH/CLI access to Nextcloud server (for
occcommands) - Python 3.11+ installed on MCP server host
- MCP server installed (see Installation Guide)
The OAuth implementation uses the following components:
MCP Client ←→ MCP Server (Resource Server) ←→ Nextcloud (Authorization Server + APIs)
OAuth Flow Bearer Token Auth
Key Roles:
- MCP Server: OAuth Resource Server (validates tokens, provides MCP tools)
- Nextcloud
oidcapp: OAuth Authorization Server (issues tokens) - Nextcloud
user_oidcapp: Token validation middleware
For detailed architecture, see OAuth Architecture.
OAuth authentication requires two Nextcloud apps to work together.
Purpose: Makes Nextcloud an OAuth2/OIDC authorization server
Installation:
- Open Nextcloud as administrator
- Navigate to Apps → Security
- Find "OIDC" (full name: "OIDC Identity Provider")
- Click Enable or Download and enable
Provides:
- OAuth2 authorization endpoint
- Token endpoint
- User info endpoint
- JWKS endpoint
- Dynamic client registration endpoint (optional)
Purpose: Authenticates users and validates Bearer tokens
Installation:
- In Apps → Security
- Find "OpenID Connect user backend" (app ID:
user_oidc) - Click Enable or Download and enable
Provides:
- Bearer token validation against OIDC provider
- User authentication via OIDC
- Session management for authenticated users
Important
Upstream Patch Required: The user_oidc app needs a patch for Bearer token support with app-specific APIs (Notes, Calendar, etc.). The patch is pending upstream review.
Status: See Upstream Status for current PR status and workarounds.
Impact: OCS APIs work without patch, but app-specific APIs require the patch.
# Check both apps are installed and enabled
php occ app:list | grep -E "oidc|user_oidc"
# Expected output:
# - oidc: enabled
# - user_oidc: enabledBest for: Development, testing, auto-registration
- Navigate to Settings → OIDC (Administration settings)
- Enable "Allow dynamic client registration"
- (Optional) Configure client expiration:
# Default: 3600 seconds (1 hour) php occ config:app:set oidc expire_time --value "86400" # 24 hours
Best for: Production, long-running deployments
Skip the dynamic registration setting. You'll manually register clients via CLI in Step 3.
Required: Enable Bearer token validation:
# SSH into Nextcloud server
php occ config:system:set user_oidc oidc_provider_bearer_validation --value=true --type=booleanThis tells user_oidc to validate Bearer tokens against Nextcloud's OIDC Identity Provider.
Test that OIDC discovery endpoint is accessible:
curl https://your.nextcloud.instance.com/.well-known/openid-configuration | jqExpected response:
{
"issuer": "https://your.nextcloud.instance.com",
"authorization_endpoint": "https://your.nextcloud.instance.com/apps/oidc/authorize",
"token_endpoint": "https://your.nextcloud.instance.com/apps/oidc/token",
"userinfo_endpoint": "https://your.nextcloud.instance.com/apps/oidc/userinfo",
"jwks_uri": "https://your.nextcloud.instance.com/apps/oidc/jwks",
"registration_endpoint": "https://your.nextcloud.instance.com/apps/oidc/register",
...
}The MCP server requires PKCE (Proof Key for Code Exchange) with S256 code challenge method.
Validation: The MCP server automatically validates PKCE support at startup by checking the discovery response for code_challenge_methods_supported.
Note: If PKCE is not advertised in discovery metadata, the server logs a warning but continues (PKCE still works, it's just not advertised). See Upstream Status for tracking.
You have two options for managing OAuth clients:
Best for: Development, testing, quick deployments
How it works:
- MCP server automatically registers an OAuth client on first startup
- Uses Nextcloud's dynamic client registration endpoint
- Saves credentials to SQLite database
- Reuses stored credentials on subsequent restarts
- Re-registers automatically if credentials expire
Pros:
- Zero configuration required
- Quick setup
- Automatic credential management
Cons:
- Clients expire (default: 1 hour, configurable)
- Must have dynamic client registration enabled on Nextcloud
Configuration: Skip to Step 4 with minimal config.
Best for: Production, long-running deployments, stable environments
How it works:
- You manually register an OAuth client via Nextcloud CLI
- Provide client credentials to MCP server via environment variables
- Credentials don't expire
Pros:
- Credentials don't expire
- Stable for production
- More control over client configuration
- Better for audit trails
Cons:
- Requires manual setup
- Needs SSH/CLI access to Nextcloud server
Setup: Register a client via CLI:
# SSH into Nextcloud server
php occ oidc:create \
--name="Nextcloud MCP Server" \
--type=confidential \
--redirect-uri="http://localhost:8000/oauth/callback"
# Example output:
# Client ID: abc123xyz789
# Client Secret: secret456def012
# Save these credentials for Step 4Important: Adjust --redirect-uri to match your MCP server URL:
- Local:
http://localhost:8000/oauth/callback - Remote:
http://your-server:8000/oauth/callback - Custom port:
http://your-server:PORT/oauth/callback
The redirect URI must be:
{NEXTCLOUD_MCP_SERVER_URL}/oauth/callback
Create or update your .env file with OAuth configuration.
# Copy sample if needed
cp env.sample .env
# Edit .env
cat > .env << 'EOF'
# Nextcloud Instance
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
# Leave EMPTY for OAuth mode (do not set USERNAME/PASSWORD)
NEXTCLOUD_USERNAME=
NEXTCLOUD_PASSWORD=
# Optional: MCP server URL (for OAuth callbacks)
NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
EOF# Copy sample if needed
cp env.sample .env
# Edit .env
cat > .env << 'EOF'
# Nextcloud Instance
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
# OAuth Client Credentials (from Step 3)
NEXTCLOUD_OIDC_CLIENT_ID=abc123xyz789
NEXTCLOUD_OIDC_CLIENT_SECRET=secret456def012
# MCP server URL (must match redirect URI)
NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
# Leave EMPTY for OAuth mode
NEXTCLOUD_USERNAME=
NEXTCLOUD_PASSWORD=
EOF| Variable | Required | Default | Description |
|---|---|---|---|
NEXTCLOUD_HOST |
✅ Yes | - | Full URL of Nextcloud instance |
NEXTCLOUD_OIDC_CLIENT_ID |
- | OAuth client ID | |
NEXTCLOUD_OIDC_CLIENT_SECRET |
- | OAuth client secret | |
NEXTCLOUD_MCP_SERVER_URL |
http://localhost:8000 |
MCP server URL for callbacks | |
NEXTCLOUD_USERNAME |
❌ Must be empty | - | Leave empty for OAuth |
NEXTCLOUD_PASSWORD |
❌ Must be empty | - | Leave empty for OAuth |
See Configuration Guide for all options.
# Load from .env file
export $(grep -v '^#' .env | xargs)
# Verify key variables are set
echo "NEXTCLOUD_HOST: $NEXTCLOUD_HOST"
echo "NEXTCLOUD_MCP_SERVER_URL: $NEXTCLOUD_MCP_SERVER_URL"# Start with OAuth mode
uv run nextcloud-mcp-server --oauth
# Or with custom options
uv run nextcloud-mcp-server --oauth --port 8000 --log-level infoLook for these success messages:
For Mode A (Auto-registration):
INFO OAuth mode detected (NEXTCLOUD_USERNAME/PASSWORD not set)
INFO Configuring MCP server for OAuth mode
INFO Performing OIDC discovery: https://your.nextcloud.instance.com/.well-known/openid-configuration
✓ PKCE support validated: ['S256']
INFO OIDC discovery successful
INFO Attempting dynamic client registration...
INFO Dynamic client registration successful
INFO OAuth client ready: <client-id>...
INFO Saved OAuth client credentials to SQLite database
INFO OAuth initialization complete
INFO MCP server ready at http://127.0.0.1:8000
For Mode B (Pre-configured):
INFO OAuth mode detected (NEXTCLOUD_USERNAME/PASSWORD not set)
INFO Configuring MCP server for OAuth mode
INFO Performing OIDC discovery: https://your.nextcloud.instance.com/.well-known/openid-configuration
✓ PKCE support validated: ['S256']
INFO OIDC discovery successful
INFO Using pre-configured OAuth client: abc123xyz789
INFO OAuth initialization complete
INFO MCP server ready at http://127.0.0.1:8000
| Issue | Solution |
|---|---|
| "OAuth mode requires NEXTCLOUD_HOST" | Set NEXTCLOUD_HOST in .env |
| "OIDC discovery failed" | Verify Nextcloud URL and network connectivity |
| "Dynamic registration failed" | Enable dynamic registration in OIDC app settings |
| "PKCE validation failed" | See Upstream Status |
See OAuth Troubleshooting for detailed solutions.
The MCP Inspector provides a web UI for testing:
# In a new terminal
uv run mcp dev
# Opens browser at http://localhost:6272In the MCP Inspector UI:
- Enter server URL:
http://localhost:8000/mcp - Click Connect
- Complete OAuth flow in browser popup:
- Login to Nextcloud
- Authorize MCP server access
- Redirected back to MCP Inspector
- Test tools:
- Try
nc_notes_create_note - Try
nc_notes_search_notes - Try
nc_calendar_list_events
- Try
# Get an OAuth token (you'll need to implement client flow or extract from browser)
TOKEN="your_access_token_here"
# Test OCS API (should work)
curl -H "Authorization: Bearer $TOKEN" \
"$NEXTCLOUD_HOST/ocs/v2.php/cloud/capabilities?format=json" \
-H "OCS-APIRequest: true"
# Test Notes API (requires upstream patch)
curl -H "Authorization: Bearer $TOKEN" \
"$NEXTCLOUD_HOST/apps/notes/api/v1/notes"Check MCP server logs for token validation:
# Start server with debug logging
uv run nextcloud-mcp-server --oauth --log-level debug
# Look for:
# DEBUG Token validation via userinfo endpoint
# DEBUG Token validated successfully for user: username-
Use Pre-configured Clients (Mode B)
- More stable
- Better audit trails
- No expiration issues
-
Secure Credential Storage
# Set restrictive permissions on environment file chmod 600 .env # Database permissions are handled automatically
-
Use HTTPS for MCP Server
- Especially important for remote access
- Use reverse proxy (nginx, Apache) with SSL
-
Restrict Redirect URIs
- Only register necessary redirect URIs
- Use specific URLs (not wildcards)
-
MCP Server URL
- Must be accessible to OAuth clients
- Must match redirect URI registered with Nextcloud
- For Docker: expose port and use correct host
-
Network Configuration
- MCP server must reach Nextcloud (OIDC endpoints)
- OAuth clients must reach MCP server (callbacks)
- OAuth clients must reach Nextcloud (authorization flow)
-
Process Management
- Use systemd, supervisord, or Docker for MCP server
- Ensure automatic restart on failure
- Monitor logs for OAuth errors
version: '3'
services:
nextcloud-mcp:
image: ghcr.io/cbcoutinho/nextcloud-mcp-server:latest
ports:
- "127.0.0.1:8000:8000"
environment:
NEXTCLOUD_HOST: https://your.nextcloud.instance.com
NEXTCLOUD_OIDC_CLIENT_ID: ${NEXTCLOUD_OIDC_CLIENT_ID}
NEXTCLOUD_OIDC_CLIENT_SECRET: ${NEXTCLOUD_OIDC_CLIENT_SECRET}
NEXTCLOUD_MCP_SERVER_URL: http://your-server:8000
volumes:
- ./data:/app/data # For SQLite database persistence
command: ["--oauth", "--transport", "streamable-http"]
restart: unless-stopped[Unit]
Description=Nextcloud MCP Server (OAuth)
After=network.target
[Service]
Type=simple
User=mcp
WorkingDirectory=/opt/nextcloud-mcp-server
Environment="NEXTCLOUD_HOST=https://your.nextcloud.instance.com"
Environment="NEXTCLOUD_OIDC_CLIENT_ID=abc123xyz789"
Environment="NEXTCLOUD_OIDC_CLIENT_SECRET=secret456def012"
Environment="NEXTCLOUD_MCP_SERVER_URL=http://your-server:8000"
ExecStart=/opt/nextcloud-mcp-server/.venv/bin/nextcloud-mcp-server --oauth
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target-
Log Monitoring
# Watch for OAuth errors tail -f /var/log/nextcloud-mcp/server.log | grep -i "oauth\|token"
-
Token Expiration (Mode A only)
- Monitor for "Stored client has expired" messages
- Consider increasing expiration or switching to Mode B
-
Upstream Patches
- Subscribe to Upstream Status
- Plan to update when patches are merged
For OAuth-specific issues, see OAuth Troubleshooting.
Common issues:
- OAuth Architecture - Understand how OAuth works
- OAuth Troubleshooting - Solve common issues
- Upstream Status - Track required patches
- Configuration - All environment variables
- Running the Server - Additional server options
- Authentication Overview - OAuth vs BasicAuth comparison
- Quick Start Guide - 5-minute setup for development
- MCP Specification - MCP protocol details
- RFC 6749 - OAuth 2.0 Framework
- RFC 7636 - PKCE Extension