feat(helm): add login-flow auth mode to Helm chart (ADR-022)
Add Login Flow v2 as a fourth auth mode alongside basic, multi-user-basic, and oauth. This enables multi-user deployments using Nextcloud's native Login Flow v2 without requiring OAuth patches to user_oidc. - Add loginFlow section to values.yaml with token encryption config - Add login-flow env vars, args, volume mounts to deployment.yaml - Add login-flow secret and oauth-storage PVC templates - Add loginFlowSecretName helper, update dataStorageEnabled - Add multi-user-basic and login-flow sections to NOTES.txt - Add version footer and ArtifactHub changelog annotations - Update README with 4 auth modes and docker-compose profiles Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,15 @@ http://127.0.0.1:8000/sse
|
|||||||
http://127.0.0.1:8000/mcp
|
http://127.0.0.1:8000/mcp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Docker Compose Profiles** (for development/testing):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile single-user up -d # Port 8000
|
||||||
|
docker compose --profile multi-user-basic up -d # Port 8003
|
||||||
|
docker compose --profile oauth up -d # Port 8001
|
||||||
|
docker compose --profile login-flow up -d # Port 8004
|
||||||
|
```
|
||||||
|
|
||||||
**Next Steps:**
|
**Next Steps:**
|
||||||
- Connect your MCP client (Claude Desktop, IDEs, `mcp dev`, etc.)
|
- Connect your MCP client (Claude Desktop, IDEs, `mcp dev`, etc.)
|
||||||
- See [docs/installation.md](docs/installation.md) for other deployment options (local, Kubernetes)
|
- See [docs/installation.md](docs/installation.md) for other deployment options (local, Kubernetes)
|
||||||
@@ -99,25 +108,33 @@ Want to see another Nextcloud app supported? [Open an issue](https://github.com/
|
|||||||
|
|
||||||
### Authentication Modes
|
### Authentication Modes
|
||||||
|
|
||||||
The server supports three authentication modes:
|
The server supports four authentication modes:
|
||||||
|
|
||||||
**Single-User Mode (BasicAuth):**
|
**Single-User (BasicAuth):**
|
||||||
- One set of credentials shared by all MCP clients
|
- One set of credentials shared by all MCP clients
|
||||||
- Simple setup: username + app password in environment variables
|
- Simple setup: username + app password in environment variables
|
||||||
- All clients access Nextcloud as the same user
|
- All clients access Nextcloud as the same user
|
||||||
- Best for: Personal use, development, single-user deployments
|
- Best for: Personal use, development, single-user deployments
|
||||||
|
|
||||||
**Multi-User Mode (OAuth):**
|
**Multi-User (BasicAuth Pass-Through):**
|
||||||
|
- MCP clients send credentials via Authorization header
|
||||||
|
- Server passes through to Nextcloud (stateless by default)
|
||||||
|
- Optional offline access for background operations (`ENABLE_MULTI_USER_BASIC_AUTH=true`)
|
||||||
|
- Best for: Multi-user setups without OAuth infrastructure
|
||||||
|
|
||||||
|
**Multi-User (OAuth):**
|
||||||
- Each MCP client authenticates separately with their own Nextcloud account
|
- Each MCP client authenticates separately with their own Nextcloud account
|
||||||
- Per-user scopes and permissions (clients only see tools they're authorized for)
|
- Per-user scopes and permissions (clients only see tools they're authorized for)
|
||||||
- More secure: tokens expire, credentials never shared with server
|
- More secure: tokens expire, credentials never shared with server
|
||||||
- Best for: Teams, multi-user deployments, production environments with multiple users
|
- Best for: Teams, multi-user deployments, production environments with multiple users
|
||||||
|
- Requires: Patches to the `user_oidc` app (experimental)
|
||||||
|
|
||||||
**Hybrid Mode (Multi-User BasicAuth + OAuth):**
|
**Multi-User (Login Flow v2):**
|
||||||
- MCP clients use BasicAuth (simple, stateless)
|
- Uses Nextcloud's native Login Flow v2 to obtain per-user app passwords
|
||||||
- Admin operations use OAuth (webhooks, background sync)
|
- No OAuth patches required — works with stock Nextcloud
|
||||||
- Best for: Nextcloud deployments with admin-managed webhooks and semantic search
|
- Each user authenticates via browser, server manages app passwords
|
||||||
- Requires: `ENABLE_MULTI_USER_BASIC_AUTH=true` + `ENABLE_OFFLINE_ACCESS=true`
|
- Best for: Multi-user deployments without OAuth infrastructure (`ENABLE_LOGIN_FLOW=true`)
|
||||||
|
- Experimental: See [ADR-022](docs/ADR-022-deployment-mode-consolidation.md) for details
|
||||||
|
|
||||||
See [docs/authentication.md](docs/authentication.md) for detailed setup instructions.
|
See [docs/authentication.md](docs/authentication.md) for detailed setup instructions.
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,15 @@ annotations:
|
|||||||
# Grafana dashboard support
|
# Grafana dashboard support
|
||||||
grafana_dashboard: "true"
|
grafana_dashboard: "true"
|
||||||
grafana_dashboard_folder: "Nextcloud MCP"
|
grafana_dashboard_folder: "Nextcloud MCP"
|
||||||
|
artifacthub.io/changes: |
|
||||||
|
- kind: added
|
||||||
|
description: Login Flow v2 auth mode for Helm chart (ADR-022)
|
||||||
|
- kind: added
|
||||||
|
description: Multi-user BasicAuth guidance in post-install NOTES
|
||||||
|
- kind: added
|
||||||
|
description: Version and changelog info in post-install NOTES
|
||||||
|
- kind: changed
|
||||||
|
description: Updated appVersion to 0.64.4
|
||||||
dependencies:
|
dependencies:
|
||||||
- name: qdrant
|
- name: qdrant
|
||||||
version: "1.17.0"
|
version: "1.17.0"
|
||||||
|
|||||||
@@ -57,6 +57,28 @@ Your Nextcloud MCP Server has been deployed in {{ .Values.auth.mode }} authentic
|
|||||||
|
|
||||||
IMPORTANT: OAuth mode is experimental and requires patches to the user_oidc app.
|
IMPORTANT: OAuth mode is experimental and requires patches to the user_oidc app.
|
||||||
See: https://github.com/cbcoutinho/nextcloud-mcp-server#authentication
|
See: https://github.com/cbcoutinho/nextcloud-mcp-server#authentication
|
||||||
|
{{- else if eq .Values.auth.mode "multi-user-basic" }}
|
||||||
|
|
||||||
|
3. Multi-User BasicAuth Mode (Pass-Through):
|
||||||
|
- Users provide credentials via Authorization header
|
||||||
|
- Connected to: {{ .Values.nextcloud.host }}
|
||||||
|
{{- if .Values.auth.multiUserBasic.enableOfflineAccess }}
|
||||||
|
- Offline access: Enabled (background operations with app passwords)
|
||||||
|
- Token storage: {{ .Values.auth.multiUserBasic.tokenStorageDb }}
|
||||||
|
{{- else }}
|
||||||
|
- Offline access: Disabled (stateless pass-through)
|
||||||
|
{{- end }}
|
||||||
|
{{- else if eq .Values.auth.mode "login-flow" }}
|
||||||
|
|
||||||
|
3. Login Flow v2 Mode (Experimental, ADR-022):
|
||||||
|
- Server URL: {{ include "nextcloud-mcp-server.mcpServerUrl" . }}
|
||||||
|
- Connected to: {{ .Values.nextcloud.host }}
|
||||||
|
- Token storage: {{ .Values.auth.loginFlow.tokenStorageDb }}
|
||||||
|
|
||||||
|
Users authenticate via Nextcloud's native Login Flow v2 — no OAuth patches required.
|
||||||
|
Each user gets a per-device app password managed by the MCP server.
|
||||||
|
|
||||||
|
IMPORTANT: Login Flow v2 is experimental. See ADR-022 for details.
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- if .Values.documentProcessing.enabled }}
|
{{- if .Values.documentProcessing.enabled }}
|
||||||
@@ -169,6 +191,12 @@ After migrating, remove the deprecated settings:
|
|||||||
================================================================================
|
================================================================================
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
Deployed version:
|
||||||
|
- Chart: {{ .Chart.Version }}
|
||||||
|
- App: {{ .Chart.AppVersion }}
|
||||||
|
|
||||||
|
Full changelog: https://github.com/cbcoutinho/nextcloud-mcp-server/blob/master/charts/nextcloud-mcp-server/CHANGELOG.md
|
||||||
|
|
||||||
For more information and documentation:
|
For more information and documentation:
|
||||||
- GitHub: https://github.com/cbcoutinho/nextcloud-mcp-server
|
- GitHub: https://github.com/cbcoutinho/nextcloud-mcp-server
|
||||||
- Documentation: https://github.com/cbcoutinho/nextcloud-mcp-server#readme
|
- Documentation: https://github.com/cbcoutinho/nextcloud-mcp-server#readme
|
||||||
|
|||||||
@@ -105,6 +105,17 @@ Create the name of the secret to use for OAuth
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the secret to use for Login Flow v2
|
||||||
|
*/}}
|
||||||
|
{{- define "nextcloud-mcp-server.loginFlowSecretName" -}}
|
||||||
|
{{- if .Values.auth.loginFlow.existingSecret }}
|
||||||
|
{{- .Values.auth.loginFlow.existingSecret }}
|
||||||
|
{{- else }}
|
||||||
|
{{- include "nextcloud-mcp-server.fullname" . }}-login-flow
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
Create the name of the PVC to use for OAuth storage
|
Create the name of the PVC to use for OAuth storage
|
||||||
*/}}
|
*/}}
|
||||||
@@ -147,6 +158,8 @@ Checks new dataStorage.enabled OR legacy persistence configs
|
|||||||
true
|
true
|
||||||
{{- else if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled -}}
|
{{- else if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled -}}
|
||||||
true
|
true
|
||||||
|
{{- else if eq .Values.auth.mode "login-flow" -}}
|
||||||
|
true
|
||||||
{{- else if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled -}}
|
{{- else if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled -}}
|
||||||
true
|
true
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
|
|||||||
@@ -46,8 +46,10 @@ spec:
|
|||||||
args:
|
args:
|
||||||
- "--transport"
|
- "--transport"
|
||||||
- "{{ .Values.mcp.transport }}"
|
- "{{ .Values.mcp.transport }}"
|
||||||
{{- if eq .Values.auth.mode "oauth" }}
|
{{- if or (eq .Values.auth.mode "oauth") (eq .Values.auth.mode "login-flow") }}
|
||||||
- "--oauth"
|
- "--oauth"
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq .Values.auth.mode "oauth" }}
|
||||||
- "--oauth-token-type"
|
- "--oauth-token-type"
|
||||||
- "{{ .Values.auth.oauth.tokenType }}"
|
- "{{ .Values.auth.oauth.tokenType }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -134,6 +136,21 @@ spec:
|
|||||||
name: {{ include "nextcloud-mcp-server.oauthSecretName" . }}
|
name: {{ include "nextcloud-mcp-server.oauthSecretName" . }}
|
||||||
key: {{ .Values.auth.oauth.clientSecretKey }}
|
key: {{ .Values.auth.oauth.clientSecretKey }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- else if eq .Values.auth.mode "login-flow" }}
|
||||||
|
# Login Flow v2 mode (ADR-022)
|
||||||
|
- name: ENABLE_LOGIN_FLOW
|
||||||
|
value: "true"
|
||||||
|
- name: NEXTCLOUD_MCP_SERVER_URL
|
||||||
|
value: {{ include "nextcloud-mcp-server.mcpServerUrl" . | quote }}
|
||||||
|
- name: NEXTCLOUD_PUBLIC_ISSUER_URL
|
||||||
|
value: {{ include "nextcloud-mcp-server.publicIssuerUrl" . | quote }}
|
||||||
|
- name: TOKEN_STORAGE_DB
|
||||||
|
value: {{ .Values.auth.loginFlow.tokenStorageDb | quote }}
|
||||||
|
- name: TOKEN_ENCRYPTION_KEY
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "nextcloud-mcp-server.loginFlowSecretName" . }}
|
||||||
|
key: {{ .Values.auth.loginFlow.tokenEncryptionKeyKey }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.documentProcessing.enabled }}
|
{{- if .Values.documentProcessing.enabled }}
|
||||||
# Document processing
|
# Document processing
|
||||||
@@ -282,7 +299,7 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: tmp
|
- name: tmp
|
||||||
mountPath: /tmp
|
mountPath: /tmp
|
||||||
{{- if and (eq .Values.auth.mode "oauth") .Values.auth.oauth.persistence.enabled }}
|
{{- if or (and (eq .Values.auth.mode "oauth") .Values.auth.oauth.persistence.enabled) (eq .Values.auth.mode "login-flow") }}
|
||||||
- name: oauth-storage
|
- name: oauth-storage
|
||||||
mountPath: /app/.oauth
|
mountPath: /app/.oauth
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -294,7 +311,7 @@ spec:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: tmp
|
- name: tmp
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
{{- if and (eq .Values.auth.mode "oauth") .Values.auth.oauth.persistence.enabled }}
|
{{- if or (and (eq .Values.auth.mode "oauth") .Values.auth.oauth.persistence.enabled) (eq .Values.auth.mode "login-flow") }}
|
||||||
- name: oauth-storage
|
- name: oauth-storage
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: {{ include "nextcloud-mcp-server.oauthPvcName" . }}
|
claimName: {{ include "nextcloud-mcp-server.oauthPvcName" . }}
|
||||||
|
|||||||
@@ -16,6 +16,21 @@ spec:
|
|||||||
storage: {{ .Values.auth.oauth.persistence.size }}
|
storage: {{ .Values.auth.oauth.persistence.size }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
---
|
---
|
||||||
|
{{- if eq .Values.auth.mode "login-flow" }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "nextcloud-mcp-server.fullname" . }}-oauth-storage
|
||||||
|
labels:
|
||||||
|
{{- include "nextcloud-mcp-server.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 100Mi
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
{{- if and (eq (include "nextcloud-mcp-server.dataStorageEnabled" .) "true") (not .Values.dataStorage.existingClaim) }}
|
{{- if and (eq (include "nextcloud-mcp-server.dataStorageEnabled" .) "true") (not .Values.dataStorage.existingClaim) }}
|
||||||
{{- $legacyMultiUserBasic := eq (include "nextcloud-mcp-server.legacyMultiUserBasicPersistence" .) "true" }}
|
{{- $legacyMultiUserBasic := eq (include "nextcloud-mcp-server.legacyMultiUserBasicPersistence" .) "true" }}
|
||||||
{{- $legacyQdrant := eq (include "nextcloud-mcp-server.legacyQdrantPersistence" .) "true" }}
|
{{- $legacyQdrant := eq (include "nextcloud-mcp-server.legacyQdrantPersistence" .) "true" }}
|
||||||
|
|||||||
@@ -45,3 +45,17 @@ data:
|
|||||||
{{ .Values.auth.oauth.clientSecretKey }}: {{ .Values.auth.oauth.clientSecret | b64enc | quote }}
|
{{ .Values.auth.oauth.clientSecretKey }}: {{ .Values.auth.oauth.clientSecret | b64enc | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
---
|
||||||
|
{{- if eq .Values.auth.mode "login-flow" }}
|
||||||
|
{{- if not .Values.auth.loginFlow.existingSecret }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "nextcloud-mcp-server.fullname" . }}-login-flow
|
||||||
|
labels:
|
||||||
|
{{- include "nextcloud-mcp-server.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{ .Values.auth.loginFlow.tokenEncryptionKeyKey }}: {{ .Values.auth.loginFlow.tokenEncryptionKey | b64enc | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|||||||
@@ -40,12 +40,13 @@ nextcloud:
|
|||||||
publicIssuerUrl: ""
|
publicIssuerUrl: ""
|
||||||
|
|
||||||
# Authentication configuration
|
# Authentication configuration
|
||||||
# Choose one mode: "basic", "multi-user-basic", or "oauth"
|
# Choose one mode: "basic", "multi-user-basic", "oauth", or "login-flow"
|
||||||
auth:
|
auth:
|
||||||
# Authentication mode: "basic", "multi-user-basic", or "oauth"
|
# Authentication mode: "basic", "multi-user-basic", "oauth", or "login-flow"
|
||||||
# basic: Single-user with username/password (recommended for personal use)
|
# basic: Single-user with username/password (recommended for personal use)
|
||||||
# multi-user-basic: Multi-user with BasicAuth pass-through (credentials in request headers)
|
# multi-user-basic: Multi-user with BasicAuth pass-through (credentials in request headers)
|
||||||
# oauth: Uses OAuth2/OIDC (experimental, requires patches)
|
# oauth: Uses OAuth2/OIDC (experimental, requires patches)
|
||||||
|
# login-flow: Multi-user via Nextcloud Login Flow v2 (experimental, ADR-022)
|
||||||
mode: basic
|
mode: basic
|
||||||
|
|
||||||
# Basic authentication settings (single-user mode)
|
# Basic authentication settings (single-user mode)
|
||||||
@@ -139,6 +140,21 @@ auth:
|
|||||||
# Use existing PVC
|
# Use existing PVC
|
||||||
existingClaim: ""
|
existingClaim: ""
|
||||||
|
|
||||||
|
# Login Flow v2 settings (experimental, ADR-022)
|
||||||
|
# Uses Nextcloud's native Login Flow v2 to obtain app passwords per user.
|
||||||
|
# No OAuth patches required — works with stock Nextcloud.
|
||||||
|
# See: docs/ADR-022-deployment-mode-consolidation.md
|
||||||
|
loginFlow:
|
||||||
|
# Token encryption key (required, ignored if existingSecret is set)
|
||||||
|
# Generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
||||||
|
tokenEncryptionKey: ""
|
||||||
|
# Token storage database path
|
||||||
|
tokenStorageDb: "/app/data/tokens.db"
|
||||||
|
# Use existing secret instead of creating one
|
||||||
|
existingSecret: ""
|
||||||
|
# Key in the existing secret
|
||||||
|
tokenEncryptionKeyKey: "token_encryption_key"
|
||||||
|
|
||||||
# Data Storage Configuration
|
# Data Storage Configuration
|
||||||
# Persistent volume for /app/data directory
|
# Persistent volume for /app/data directory
|
||||||
# Used for: token databases, qdrant persistent storage, and any app data
|
# Used for: token databases, qdrant persistent storage, and any app data
|
||||||
@@ -147,6 +163,7 @@ dataStorage:
|
|||||||
# Enable persistent storage for /app/data
|
# Enable persistent storage for /app/data
|
||||||
# Set to true when using:
|
# Set to true when using:
|
||||||
# - Multi-user basic auth with offline access (stores tokens.db)
|
# - Multi-user basic auth with offline access (stores tokens.db)
|
||||||
|
# - Login flow mode (stores app passwords in tokens.db)
|
||||||
# - Qdrant persistent mode (stores vector database)
|
# - Qdrant persistent mode (stores vector database)
|
||||||
# - Any feature requiring persistent app data
|
# - Any feature requiring persistent app data
|
||||||
# Set to false for basic auth without persistence (uses emptyDir)
|
# Set to false for basic auth without persistence (uses emptyDir)
|
||||||
|
|||||||
Reference in New Issue
Block a user