12 KiB
Testing OIDC Consent Feature
This guide explains how to test the OIDC consent feature using the development version of the OIDC app mounted into the Docker environment.
Setup
Volume Mount Configuration
The development OIDC app is mounted from ~/Software/oidc into the container at /opt/apps/oidc:
# docker-compose.yml
volumes:
- ../Software/oidc:/opt/apps/oidc:ro
Why mount outside /var/www/html/?
- The Nextcloud container uses
rsyncto initialize/var/www/html/from the image - Mounting inside that path causes conflicts (rsync tries to delete mounted directories)
- Mounting to
/opt/apps/oidcavoids rsync entirely - Nextcloud supports multiple app directories via the
apps_pathsconfiguration
How multiple app paths work:
- Nextcloud can load apps from multiple directories
- The post-installation hook registers
/opt/appsas an additional app directory (index 2) - Apps in default paths (index 0 and 1) are still available
- All directories are scanned for apps, but
/opt/appsis read-only
This setup allows you to:
- Test changes without rebuilding containers
- Avoid needing npm/node in the container (JS already built on host)
- Iterate quickly on development
- Install other Nextcloud apps normally (custom_apps remains writable)
How It Works
- Mount Development App: Docker mounts
~/Software/oidcto/opt/apps/oidc(outside Nextcloud's path) - Register App Path: The
10-install-oidc-app.shhook configures/opt/appsas an additional app directory - Enable App: The hook enables the OIDC app from
/opt/apps/oidc - Run Migrations: Nextcloud detects pending migrations and runs them automatically
- Configure OIDC: Dynamic client registration and PKCE are enabled
Starting the Stack
cd ~/Projects/nextcloud-mcp-server
# Start fresh (recommended for first test)
docker compose down -v
docker compose up -d
# Wait for initialization (check logs)
docker compose logs -f app
The post-installation hooks will:
- Configure custom_apps path (already done)
- Enable OIDC app from mounted directory
- Run database migrations (including consent table creation)
- Configure OIDC settings
Verifying Installation
Before Container Restart
Before running docker compose up -d, the consent feature will NOT be active:
- ❌ No
oc_oidc_user_consentstable in database - ❌ Migration 0015 not applied yet
- ❌ ConsentController class not loaded
- ❌ Consent routes not registered
You can verify this with:
# Check migrations applied (should stop at 0014)
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "SELECT version FROM oc_migrations WHERE app = 'oidc' ORDER BY version DESC LIMIT 3;" nextcloud
# Check for consent table (should return empty)
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "SHOW TABLES LIKE 'oc_oidc_user_consents';" nextcloud
After Container Restart
After docker compose up -d with the mounted OIDC directory, the consent feature should be active:
- ✅
oc_oidc_user_consentstable exists - ✅ Migration 0015 (Version0015Date20251123100100) applied
- ✅ ConsentController routes registered
- ✅ Consent screen appears during OAuth flows
Check App Status
docker compose exec app php occ app:list | grep -A 2 oidc
Expected output:
- oidc: 1.10.0 (enabled)
Verify App Paths Configuration
Verify that /opt/apps is registered as an additional app directory:
# Check configured app paths
docker compose exec app php occ config:system:get apps_paths
# Verify the mount is accessible
docker compose exec app ls -la /opt/apps/oidc/
# Verify custom_apps is writable (for normal app installation)
docker compose exec -u www-data app touch /var/www/html/custom_apps/.test && echo "✅ custom_apps is writable" || echo "❌ custom_apps NOT writable"
docker compose exec app rm -f /var/www/html/custom_apps/.test
Expected: Output should show multiple app paths including index 2 (/opt/apps).
Verify Consent Files
# Check controller exists in mounted location
docker compose exec app ls -la /opt/apps/oidc/lib/Controller/ConsentController.php
# Check Vue component exists
docker compose exec app ls -la /opt/apps/oidc/src/Consent.vue
# Check built JS exists
docker compose exec app ls -lh /opt/apps/oidc/js/oidc-consent.js
Verify Database Migration
Note: These checks will only pass after restarting containers with the mounted OIDC app.
# Check if consent table exists
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "SHOW TABLES LIKE 'oc_oidc_user_consents';"
# Check table structure
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "DESCRIBE oc_oidc_user_consents;"
# Verify migration 0015 was applied
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "SELECT app, version FROM oc_migrations WHERE app = 'oidc' AND version LIKE '%0015%';"
Expected table structure:
- id: int(10) unsigned, auto_increment, primary key
- user_id: varchar(256), not null
- client_id: int(10) unsigned, not null
- scopes_granted: varchar(512), not null
- created_at: int(10) unsigned, not null
- updated_at: int(10) unsigned, not null
- expires_at: int(10) unsigned, nullable
Verify Routes
docker compose exec app php occ router:list | grep consent
Expected output:
oidc.Consent.show GET apps/oidc/consent
oidc.Consent.grant POST apps/oidc/consent/grant
oidc.Consent.deny POST apps/oidc/consent/deny
Testing the Consent Flow
1. Create an OAuth Client
The JWT client is automatically created by the post-installation hooks:
# Check if JWT client exists
docker compose exec app cat /var/www/html/.oauth-jwt/nextcloud_oauth_client.json
2. Initiate Authorization Flow
You can test using the MCP OAuth container or manually:
Option A: Using MCP OAuth container
# The mcp-oauth container will trigger the OAuth flow
docker compose logs -f mcp-oauth
Option B: Manual browser test
- Get client_id from the JWT client JSON
- Visit in browser:
http://localhost:8080/apps/oidc/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=http://localhost:8001/oauth/callback&scope=openid+profile+email+mcp:notes:read+mcp:notes:write&state=test123
3. Expected Behavior
First Authorization:
- User logs in (if not already authenticated)
- Consent screen appears with:
- Application name: "Nextcloud MCP Server JWT"
- List of requested scopes with descriptions:
- ✓ Basic authentication (openid) - required, cannot deselect
- ✓ Profile information (profile)
- ✓ Email address (email)
- ✓ mcp:notes:read (custom scope, shown as-is)
- ✓ mcp:notes:write (custom scope, shown as-is)
- "Allow" and "Deny" buttons
- User selects scopes and clicks "Allow"
- Authorization proceeds with selected scopes
- Consent is stored in database
Subsequent Authorizations:
- Same scopes → No consent screen (uses stored consent)
- Different scopes → Consent screen appears again
- If user clicks "Deny" → Returns
error=access_deniedto client
4. Verify Consent Stored
After granting consent:
# View all stored consents with formatted timestamps
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "
SELECT
user_id,
client_id,
scopes_granted,
FROM_UNIXTIME(created_at) as created,
FROM_UNIXTIME(updated_at) as updated,
FROM_UNIXTIME(expires_at) as expires
FROM oc_oidc_user_consents;
" nextcloud
# Or for a compact view:
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "SELECT * FROM oc_oidc_user_consents;" nextcloud
Troubleshooting
Consent Screen Not Appearing
Check browser console (F12 → Console tab):
# Look for JS errors like:
Failed to load resource: js/oidc-consent.js
Check Nextcloud logs:
docker compose exec app tail -f /var/www/html/data/nextcloud.log | grep -i consent
Verify JS file loaded:
# Check file exists and has correct size (~73KB)
docker compose exec app ls -lh /opt/apps/oidc/js/oidc-consent.js
Clear Nextcloud caches:
docker compose exec app php occ maintenance:repair
docker compose restart app
Migration Didn't Run
Check which migrations have been applied:
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "SELECT app, version FROM oc_migrations WHERE app = 'oidc' ORDER BY version;" nextcloud
Expected to see Version0015Date20251123100100 in the list.
Manually trigger migrations:
# Disable and re-enable app (triggers all pending migrations)
docker compose exec app php occ app:disable oidc
docker compose exec app php occ app:enable oidc
# Verify migration 0015 was applied
docker compose exec -T db mariadb -u nextcloud -ppassword nextcloud -e "SELECT version FROM oc_migrations WHERE app = 'oidc' AND version LIKE '%0015%';" nextcloud
Routes Not Registered
If router:list doesn't show consent routes:
# The autoloader might not have picked up new classes
# Restart the container
docker compose restart app
# Wait for it to be ready
sleep 10
# Try again
docker compose exec app php occ router:list | grep consent
If still not working, check if ConsentController is accessible:
docker compose exec app php -r "
require_once '/var/www/html/lib/base.php';
\$class = 'OCA\\OIDCIdentityProvider\\Controller\\ConsentController';
if (class_exists(\$class)) {
echo \"Class exists\n\";
} else {
echo \"Class not found\n\";
}
"
Making Changes
Frontend Changes (Vue.js)
- Edit source file on host:
cd ~/Software/oidc
# Edit src/Consent.vue
- Rebuild JS:
npm run build
- Refresh browser (container sees changes immediately via volume mount at /opt/apps/oidc)
Backend Changes (PHP)
- Edit files on host:
cd ~/Software/oidc
# Edit lib/Controller/ConsentController.php or other PHP files
-
Changes are immediately visible (PHP is interpreted, no build step)
-
For new classes or major changes, restart container:
docker compose restart app
Database Schema Changes
If you modify the migration:
# Changes won't be picked up if migration already ran
# Need to recreate the database:
docker compose down -v # Removes volumes
docker compose up -d # Fresh start with clean DB
Cleanup
Reset Everything
cd ~/Projects/nextcloud-mcp-server
docker compose down -v
This removes:
- All containers
- Database volume (all data)
- OAuth client credentials
Keep Data, Restart App
docker compose restart app
This preserves:
- Database (consents, clients, users)
- OAuth client credentials
Development Workflow Summary
- Make changes in
~/Software/oidc - Build JS if you changed Vue files:
npm run build - Test immediately - refresh browser or restart container
- No need to rebuild Docker images or reinstall app
- Iterate quickly with instant feedback
Production Deployment
When ready to deploy:
-
Create patch file (already done):
cd ~/Software/oidc git format-patch master --stdout > user-consent-feature.patch -
Test patch in clean environment:
# In a production-like environment cd /path/to/production/oidc git apply user-consent-feature.patch npm install npm run build php occ app:disable oidc php occ app:enable oidc -
Verify migration runs automatically on app enable
-
Submit pull request to upstream repository