Fixes 401 errors after first token refresh when using IdPs that
implement refresh token rotation (Keycloak, modern OAuth providers).
**Root Cause**:
McpTokenStorage::getAccessToken() was discarding the new refresh token
returned by the IdP after successful refresh, always keeping the old one.
This caused:
- First refresh: works (uses original refresh token)
- Second refresh: fails with 401 (old refresh token invalidated by IdP)
**Solution**:
Use new refresh token from IdP response if provided, fall back to old
token for providers that don't rotate refresh tokens.
**Changed**:
- lib/Service/McpTokenStorage.php:184
From: $token['refresh_token'] // Always old token
To: $newTokenData['refresh_token'] ?? $token['refresh_token']
**Verified**:
ApiController already handles rotation correctly using the same pattern.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Adds a native Nextcloud app "Astroglobe" that provides:
- Personal settings: OAuth authorization for background MCP access
- Admin settings: Server status and vector sync monitoring
- API endpoints for MCP server communication
The app uses PKCE OAuth flow to obtain tokens for the MCP server,
enabling features like background vector sync per ADR-018.
Includes:
- PHP app structure (controllers, services, settings)
- Vue.js frontend components
- Docker compose mount configuration
- Installation hook for development testing
- ADR-018 documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>