docs: Implement separate clients architecture for Keycloak integration
Implements proper OAuth 2.0 separation following RFC 8707 best practices with distinct resource server and OAuth client configurations. ## Architecture Changes - Create separate "nextcloud" bearer-only client (resource server) - Configure "nextcloud-mcp-server" OAuth client with audience mapper - Audience mapper targets "nextcloud" resource server - Token flow: aud="nextcloud", azp="nextcloud-mcp-server" ## Benefits - Proper OAuth client vs resource server separation - Support for future multi-resource tokens: aud=["nextcloud", "other-service"] - RFC 8707 Resource Indicators compliance - Clear requester identification via azp claim ## Documentation Updates - Correct OAuth flow: MCP Client initiates, handles redirect, shares tokens - Explain MCP Server as protected resource architecture - Document offline_access with refresh tokens (Tier 1, current) - Document token exchange with delegation (Tier 2, future when Keycloak adds support) - Reference Keycloak issue #38279 for delegation status ## Files - keycloak/realm-export.json: Add separate clients configuration - app-hooks/post-installation/15-setup-keycloak-provider.sh: Setup user_oidc with "nextcloud" client - docs/audience-validation-setup.md: Comprehensive documentation with corrected OAuth flow and delegation comparison - docker-compose.yml: Fix Keycloak healthcheck (bash TCP instead of curl) - scripts/test_separate_clients.sh: Verification script for architecture 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+46
-1
@@ -96,14 +96,59 @@ services:
|
||||
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:26.4.2
|
||||
command: ["start-dev"]
|
||||
command: ["start-dev", "--import-realm"]
|
||||
ports:
|
||||
- 127.0.0.1:8888:8080
|
||||
environment:
|
||||
- KC_BOOTSTRAP_ADMIN_USERNAME=admin
|
||||
- KC_BOOTSTRAP_ADMIN_PASSWORD=admin
|
||||
volumes:
|
||||
- ./keycloak/realm-export.json:/opt/keycloak/data/import/realm.json:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/8080 && echo -e 'GET /realms/nextcloud-mcp HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && cat <&3 | grep -q 'HTTP/1.1 200'"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
|
||||
mcp-keycloak:
|
||||
build: .
|
||||
command: ["--transport", "streamable-http", "--oauth", "--port", "8002"]
|
||||
restart: always
|
||||
depends_on:
|
||||
keycloak:
|
||||
condition: service_healthy
|
||||
app:
|
||||
condition: service_started
|
||||
ports:
|
||||
- 127.0.0.1:8002:8002
|
||||
environment:
|
||||
# OAuth Provider: Keycloak
|
||||
- OAUTH_PROVIDER=keycloak
|
||||
- KEYCLOAK_URL=http://keycloak:8080
|
||||
- KEYCLOAK_REALM=nextcloud-mcp
|
||||
- KEYCLOAK_CLIENT_ID=nextcloud-mcp-server
|
||||
- KEYCLOAK_CLIENT_SECRET=mcp-secret-change-in-production
|
||||
- KEYCLOAK_DISCOVERY_URL=http://keycloak:8080/realms/nextcloud-mcp/.well-known/openid-configuration
|
||||
|
||||
# Nextcloud API endpoint (for accessing APIs with validated token)
|
||||
- NEXTCLOUD_HOST=http://app:80
|
||||
- NEXTCLOUD_MCP_SERVER_URL=http://localhost:8002
|
||||
- NEXTCLOUD_PUBLIC_ISSUER_URL=http://localhost:8888
|
||||
|
||||
# Refresh token storage (ADR-002 Tier 1)
|
||||
- ENABLE_OFFLINE_ACCESS=true
|
||||
- TOKEN_ENCRYPTION_KEY=${TOKEN_ENCRYPTION_KEY:-}
|
||||
- TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||
- NEXTCLOUD_OIDC_CLIENT_STORAGE=/app/.oauth/keycloak_oauth_client.json
|
||||
|
||||
# NO admin credentials - using Keycloak OAuth only!
|
||||
volumes:
|
||||
- keycloak-tokens:/app/data
|
||||
- keycloak-oauth-storage:/app/.oauth
|
||||
|
||||
volumes:
|
||||
nextcloud:
|
||||
db:
|
||||
oauth-client-storage:
|
||||
keycloak-tokens:
|
||||
keycloak-oauth-storage:
|
||||
|
||||
Reference in New Issue
Block a user