Resolves the token exchange implementation gap where get_session_client()
was implemented but never used by tools. Unifies token acquisition into a
single async get_client() method that handles both pass-through and token
exchange modes transparently.
Core Changes:
- Make get_client() async and merge token exchange logic into it
- Remove scopes parameter from token exchange (Nextcloud doesn't support OAuth scopes)
- Update all 8 tool modules to use await get_client(ctx)
- Fix provisioning decorator to skip checks in BasicAuth mode
Token Acquisition Modes:
1. BasicAuth: Returns shared client (no token operations)
2. OAuth pass-through (default): Verifies and passes Flow 1 token to Nextcloud
3. OAuth token exchange (opt-in): Exchanges Flow 1 token for ephemeral token via RFC 8693
Key Architectural Clarifications:
- Progressive Consent (Flow 1/2) = Authorization architecture
- Token Exchange = Token acquisition pattern during tool execution
- Refresh tokens from Flow 2 are NEVER used for tool calls (only background jobs)
- Nextcloud scopes are "soft-scopes" enforced by MCP server, not IdP
Documentation Updates:
- ADR-004: Added comprehensive token acquisition patterns section
- CRITICAL-TOKEN-EXCHANGE-PATTERN.md: Updated to reflect implementation status
- CLAUDE.md: Updated architectural patterns with async get_client()
Testing:
- All 36 unit tests passing
- All 4 smoke tests passing (BasicAuth mode)
- Linting issues fixed (ruff)
Configuration:
ENABLE_TOKEN_EXCHANGE=false (default) - pass-through mode
ENABLE_TOKEN_EXCHANGE=true (opt-in) - token exchange mode
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive automated integration test for Keycloak service account
token acquisition via client_credentials grant, validating ADR-002 Tier 1
implementation for external IdP mode.
Changes:
- Add keycloak_oauth_client fixture in tests/conftest.py
- Creates KeycloakOAuthClient instance for service account operations
- Session-scoped fixture with automatic cleanup
- Discovers Keycloak endpoints automatically
- Add test_keycloak_service_account_token_acquisition test
- Tests client_credentials grant token acquisition
- Verifies token response structure (access_token, token_type, expires_in)
- Validates token works with Nextcloud APIs via capabilities endpoint
- Documents limitation for Nextcloud OIDC app (integrated mode)
- Update ADR-002 documentation
- Mark automated test as complete (✅)
- Document supported providers (Keycloak ✅, Nextcloud OIDC app ❌)
- Add note that KeycloakOAuthClient is provider-agnostic
- Clarify that Nextcloud OIDC app support requires config only
Test results:
- ✅ Service account token acquired successfully (300s expiry, Bearer type)
- ✅ Token validated by Nextcloud user_oidc app
- ✅ Token works with Nextcloud capabilities API
Note: Nextcloud OIDC app (integrated mode) service account token support
not yet implemented. See app.py:631-635 for current status.
Resolves: "TODO: Automated integration tests needed for both Keycloak and
Nextcloud OIDC app" from ADR-002
This enhances the Keycloak integration test suite with comprehensive
scope-based authorization validation, matching the OIDC test structure.
Changes:
- Add 3 test users to Keycloak realm (read-only, write-only, no-custom-scopes)
- Create OAuth token fixtures with different scope combinations
- Create MCP client fixtures for each scope configuration
- Add 4 new tests validating scope-based tool filtering:
* Read-only tokens filter out write tools
* Write-only tokens filter out read tools
* Full access tokens show all 90+ tools
* No custom scopes result in zero tools
Test Results:
- All 15 Keycloak integration tests pass (11 existing + 4 new)
- Validates proper JWT scope enforcement in external IdP architecture
- Confirms security isolation when users decline custom scopes
This completes ADR-002 scope authorization testing for the Keycloak
external identity provider integration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The Nextcloud OIDC app has updated token_type parameter values:
- Changed from "Bearer" → "opaque" for opaque tokens
- Changed from "JWT" → "jwt" for JWT tokens
Updated test_dcr_token_type.py to use lowercase token_type values:
- token_type="jwt" for JWT-formatted tokens
- token_type="opaque" for opaque/bearer tokens
This fixes test failures where tests were using the old "Bearer" and
"JWT" (uppercase) values which are no longer recognized by the OIDC app.
Fixes test: test_dcr_respects_bearer_token_type
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Import recipes from URLs using schema.org metadata
- Full CRUD operations for recipes
- Search, categorize, and organize recipes
- Manage keywords/tags and categories
- Configure app settings and trigger reindexing