diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 0000000..05c8ab7 --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,264 @@ +# Design: Generic OIDC Auth for the Frontend + +## Summary + +Replace the hardcoded `keycloak-js` dependency in the frontend with `oidc-spa`, a library that implements the same OIDC flow abstracted over any OpenID Connect provider. The runtime config file changes from a Keycloak-specific schema (`auth-server-url` + `realm`) to a provider-agnostic schema (`issuer` + `client_id`). The public API surface of `src/auth/index.ts` stays the same. On the backend, delete `_authenticators.py` — the `BearerTokenAuthenticator` + `OIDCTokenValidator` stack can be declared inline in `config.yaml` via Ravnar's `ImportStringWithParams` resolution. A single `oidc` values block replaces the old `keycloak` block. + +## Goals + +- Frontend authenticates against **any OIDC-compliant identity provider** (Keycloak, Auth0, Okta, Azure AD, Google, etc.). +- All existing callers of `@/auth` — `fetch()`, `login()`, `logout()`, `getUserProfile()` — continue to work without changes. +- The `VITE_AUTH_ENABLED=false` dev bypass continues to work. +- Delete `src/ravnar_nebari_chat/_authenticators.py` — the backend auth is declared inline in `config.yaml` using Ravnar's dynamic import system. +- Single `oidc` values block in Helm for both frontend and backend config. +- Remove the dead `frontend.keycloak` block from values. + +## Non-Goals + +- Gateway-level auth. The NebariApp operator still handles ingress authentication and OIDC client provisioning; this design only touches the SPA-side auth and the backend's token validation config. +- Runtime multi-provider switching. The config declares one issuer per deployment. +- Changes to Ravnar itself. + +## Background / Motivation + +The Nebari Chat Pack frontend uses `keycloak-js` directly, which ties it to Keycloak as the identity provider. The runtime config (`public/keycloak-config.json`) uses Keycloak-specific fields (`auth-server-url`, `realm`, `resource`). + +The backend currently has a thin factory `ravnar_nebari_chat.keycloak_authenticator` that concatenates `keycloak_url` + `realm` into an issuer URL and wraps `OIDCTokenValidator` in `BearerTokenAuthenticator`. The `OIDCTokenValidator` is already fully generic — this factory is entirely wiring. With Ravnar's `ImportStringWithParams` (which recursively resolves nested `cls_or_fn` in `params`), the same wiring can be expressed declaratively in YAML, eliminating the custom Python module. + +## Design + +### 1. Library: `oidc-spa` + +Replace `keycloak-js` with [`oidc-spa`](https://docs.oidc-spa.dev/) (npm `oidc-spa`). + +**Why `oidc-spa` over alternatives:** + +| Library | Why it fits | +|---------|-------------| +| `oidc-client-ts` | Mature (2M weekly downloads), but framework-agnostic — we'd need to wire React context and TanStack Router integration ourselves. | +| `oidc-spa` | From the Keycloakify team (Keycloak experts). **First-class TanStack Router integration** (used by this project). Explicitly designed as a `keycloak-js` drop-in that works with any OIDC provider. Smaller API surface. | + +The project already uses TanStack Router, so `oidc-spa`'s native integration avoids boilerplate. The migration from `keycloak-js` is the library's primary use case. + +### 2. Runtime Config: `public/auth-config.json` + +Replace `public/keycloak-config.json` with `public/auth-config.json`. + +```json +{ + "issuer": "https://keycloak.example.com/realms/nebari", + "client_id": "nebari-chat-dev-spa" +} +``` + +**Schema:** + +| Key | Required | Description | +|-----|----------|-------------| +| `issuer` | Yes | Full OIDC issuer URL (e.g. `https://keycloak.example.com/realms/nebari`) | +| `client_id` | Yes | Public SPA client ID registered with the IdP | + +**Removed fields compared to old format:** `auth-server-url`, `realm`, `resource` — all superseded by the flat `issuer` URL. + +**Not in config (hardcoded in JS):** + +| Setting | Value | Rationale | +|---------|-------|-----------| +| `redirect_uri` | `window.location.origin` | Runtime-computed; matches how the current code passes it to keycloak.login/logout. | +| `scope` | `"openid email name"` | User explicitly chose to hardcode this. | + +### 3. `src/auth/index.ts` Changes + +The module's public API stays the same: + +```ts +export class FetchError extends Error { … } +export async function fetch(url, init?): Promise { … } +export async function login(): Promise { … } +export async function logout(): Promise { … } +export function getUserProfile(): UserProfile | null { … } +export type UserProfile = { name: string; email: string }; +``` + +**Internal changes:** + +1. **Remove `import Keycloak from 'keycloak-js'`** — replace with oidc-spa initialization. +2. **Config loading** — `fetch('/auth-config.json')` at module init instead of `new Keycloak('/keycloak-config.json')`. +3. **Initialization** — `createOidc()` from oidc-spa, wrapping the config fetch. +4. **`fetch()`** — reads the access token from the oidc-spa session instead of `keycloak.token`. +5. **`login()`** — calls `oidc.login({ redirectUri: window.location.origin })` instead of `keycloak.login()`. +6. **`logout()`** — calls `oidc.logout({ redirectUri: window.location.origin })` instead of `keycloak.logout()`. +7. **`getUserProfile()`** — reads `name` and `email` from the decoded ID token claims via oidc-spa's `getUser()` or decoded token accessor. + +The top-level `await` pattern (currently `await keycloak.init()`) stays. The `VITE_AUTH_ENABLED` guard keeps the same behavior: + +```ts +// Pseudocode of the new init flow +const AUTH_ENABLED = import.meta.env.VITE_AUTH_ENABLED === 'true'; + +let oidc: Oidc | null = null; + +if (AUTH_ENABLED) { + const configResp = await fetch('/auth-config.json'); + const config = await configResp.json(); + oidc = await createOidc({ + issuerUrl: config.issuer, + clientId: config.client_id, + redirectUri: window.location.origin, + }); +} +``` + +### 4. Caller Changes + +Zero changes to callers. All four consumption sites reference `@/auth` purely through the exported functions: + +| File | Uses | Impact | +|------|------|--------| +| `src/routes/_authenticated.tsx` | `auth.login()` | None — same function signature. | +| `src/routes/logout.tsx` | `auth.logout()` | None — same function signature. | +| `src/sidebar/userprofile.tsx` | `auth.getUserProfile()` | None — same return type. | +| `src/api/*.ts` | `auth.fetch()` | None — same function signature. | + +The `FetchError` class is also unchanged. + +### 5. Backend: Delete `_authenticators.py`, Inline Auth Config + +**Delete** `src/ravnar_nebari_chat/_authenticators.py`. The factory function is no longer needed — Ravnar's `ImportStringWithParams` resolves nested `cls_or_fn` blocks in YAML, so the `BearerTokenAuthenticator` + `OIDCTokenValidator` wiring moves into `config.yaml`. + +The backend `config.yaml` becomes: + +```yaml +security: + authenticator: + cls_or_fn: _ravnar.authenticators.BearerTokenAuthenticator + params: + token_validator: + cls_or_fn: _ravnar.authenticators.OIDCTokenValidator + params: + issuer: '{{ required "oidc.issuer is required" .Values.oidc.issuer }}' + default_permissions: + - threads:read + - threads:write + - threads:delete + - agents:read +``` + +Ravnar's `ImportStringWithParams._validate_nested` recursively processes `cls_or_fn` keys inside `params`, constructing the inner `OIDCTokenValidator` first and passing it as the `token_validator` argument to `BearerTokenAuthenticator`. + +### 6. Helm Chart Changes + +**`values.yaml` — replace `keycloak` block with `oidc` block:** + +```yaml +# Removed +keycloak: + url: "" + realm: "nebari" + clientId: "" + +# Removed (dead key — never referenced in templates) +frontend: + ... + keycloak: ... + +# Added +oidc: + # Full OIDC issuer URL, e.g. https://keycloak.example.com/realms/nebari + issuer: "" + # SPA client ID. If not set, defaults to a generated value matching the current scheme. + clientId: "" +``` + +**`templates/frontend-configmap.yaml` — generate `auth-config.json`:** + +```yaml +data: + auth-config.json: | + {{ + dict + "issuer" (required "oidc.issuer is required" .Values.oidc.issuer) + "client_id" (.Values.oidc.clientId | default (printf "%s-%s-spa" .Release.Namespace ...)) + | toPrettyJson | nindent 4 + }} +``` + +**`templates/frontend-deployment.yaml` — update volume mount path:** + +``` +mountPath: /usr/share/nginx/html/auth-config.json +subPath: auth-config.json +``` + +**`config.yaml` — backend auth config uses the same `oidc` values:** + +```yaml +security: + authenticator: + cls_or_fn: _ravnar.authenticators.BearerTokenAuthenticator + params: + token_validator: + cls_or_fn: _ravnar.authenticators.OIDCTokenValidator + params: + issuer: '{{ required "oidc.issuer is required" .Values.oidc.issuer }}' + default_permissions: + - threads:read + - threads:write + - threads:delete + - agents:read +``` + +A Keycloak default can be provided in the chart's `values.yaml`: + +```yaml +oidc: + issuer: "" + clientId: "" +``` + +The deployer sets `oidc.issuer` to the full issuer URL (e.g., `https://keycloak.example.com/realms/nebari`). For the default Nebari Keycloak deployment, this is the same URL the old `keycloak.url` + `keycloak.realm` concatenated to. + +### 7. `.env` / Dev Experience + +No changes. `VITE_AUTH_ENABLED=false` continues to bypass auth entirely. When developing against a real IdP, the developer creates a local `public/auth-config.json` (added to `.gitignore` like `.env`). + +## Tradeoffs & Risks + +| Risk | Mitigation | +|------|------------| +| **oidc-spa is newer** than `oidc-client-ts`. While actively maintained (Keycloakify team), it has a smaller userbase. | The surface area we use is narrow (init, login, logout, get token, parse ID token). If oidc-spa has issues, switching to `oidc-client-ts` is a confined change within `src/auth/index.ts`. | +| **Breaking change — `keycloak` values block removed.** Existing deployments must migrate to `oidc.issuer` + `oidc.clientId`. The old `keycloak_config`+`realm` two-value scheme is replaced by a single issuer URL. | Acceptable per user. The `required` directive in the ConfigMap template makes the fix obvious. | +| **Breaking change — `keycloak-config.json` file no longer served.** The frontend now loads `auth-config.json`. | The frontend image must be updated to load the new filename. No backward-compat shim. | +| **Removing `_authenticators.py`** — if any external deployment imports `ravnar_nebari_chat.keycloak_authenticator`, it breaks. | This is an internal module used only by the chart's `config.yaml`. No external consumers known. | +| **Backend `config.yaml` uses Ravnar-internal dotted paths** (`_ravnar.authenticators.*`). These are not a public Ravnar API and could change between versions. | The `BearerTokenAuthenticator` and `OIDCTokenValidator` classes are core to Ravnar's auth model and unlikely to change incompatibly. If they do, the factory function would have broken too — the difference is just where the import path lives. | + +## Testing Strategy + +### Dev-mode bypass + +- `VITE_AUTH_ENABLED=false` — the auth module skips OIDC init entirely, `fetch()` adds no bearer header, `login()`/`logout()` are no-ops. Existing behavior preserved. + +### Unit / self-check + +- The auth module has no existing tests. Add a minimal assertion-based `__main__` self-check in `src/auth/index.ts` that validates `public/auth-config.json` can be loaded and parsed, and that an `issuer` URL looks like a URL (starts with `https://`). This catches config issues at import time rather than at login. + +### Manual smoke test (Keycloak) + +1. Deploy with `oidc.issuer` and `oidc.clientId` set (e.g. `oidc.issuer: https://keycloak.example.com/realms/nebari`). +2. Visit the app — should redirect to Keycloak login. +3. Log in — should return to the app with user profile shown in sidebar. +4. Log out — should redirect to Keycloak logout and return to the app's login page. +5. Refresh the page while authenticated — session persists. + +### Manual smoke test (alternative OIDC provider) + +1. Deploy with `oidc.issuer` pointed at a non-Keycloak OIDC provider (e.g., Auth0 or Okta dev tenant). +2. Repeat steps 2–5 above. + +### Browser storage + +- Verify that no `keycloak-*` keys remain in `localStorage` or `sessionStorage` after the migration. `oidc-spa` uses `oidc-spa:*` prefixed keys — the old keys are orphaned but harmless. + +## Open Questions + +*(None — all decisions resolved during design.)* diff --git a/backend/src/ravnar_nebari_chat/_authenticators.py b/backend/src/ravnar_nebari_chat/_authenticators.py deleted file mode 100644 index f198caa..0000000 --- a/backend/src/ravnar_nebari_chat/_authenticators.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import annotations - -from ravnar.authenticators import ALL_PERMISSIONS, BearerTokenAuthenticator, OIDCTokenValidator - - -def keycloak_authenticator(*, keycloak_url: str, realm: str = "nebari") -> BearerTokenAuthenticator: - return BearerTokenAuthenticator( - OIDCTokenValidator( - issuer=f"{keycloak_url.rstrip('/')}/realms/{realm}", - default_permissions=list(ALL_PERMISSIONS), - ) - ) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a4bdbd8..6e46c2a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -35,9 +35,9 @@ "jotai": "^2.20.1", "json-edit-react": "^1.30.2", "katex": "^0.17.0", - "keycloak-js": "^26.2.4", "leaflet": "^1.9.4", "lucide-react": "^1.22.0", + "oidc-spa": "^10.2.6", "react": "^19.1.1", "react-dom": "^19.1.1", "react-markdown": "^10.1.0", @@ -380,9 +380,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -400,9 +397,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -420,9 +414,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -440,9 +431,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -1664,9 +1652,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1684,9 +1669,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1704,9 +1686,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1724,9 +1703,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1744,9 +1720,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1764,9 +1737,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1986,9 +1956,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2006,9 +1973,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2026,9 +1990,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2046,9 +2007,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3492,15 +3450,6 @@ "katex": "cli.js" } }, - "node_modules/keycloak-js": { - "version": "26.2.4", - "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.4.tgz", - "integrity": "sha512-PnXpR3ubETGOt0B/Qt2lxmPbkZr5bc3vlQsOqDoTPPQsZRp7JjhTKxlJ187uWh8qJhvBab6Gsjb06a8ayOPfuw==", - "license": "Apache-2.0", - "workspaces": [ - "test" - ] - }, "node_modules/leaflet": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", @@ -4748,6 +4697,52 @@ "devOptional": true, "license": "MIT" }, + "node_modules/oidc-spa": { + "version": "10.2.7", + "resolved": "https://registry.npmjs.org/oidc-spa/-/oidc-spa-10.2.7.tgz", + "integrity": "sha512-CWc54OHm+5462v7OA7wliyTIZhYsuxwsc3QkMrFFsrCqw2QS+KANnuwfS7jRL+3DEaZBN0ucv/89Sqq8ye0jZQ==", + "license": "MIT", + "peerDependencies": { + "@angular/common": "*", + "@angular/core": "*", + "@angular/router": "*", + "@nuxt/kit": "*", + "@tanstack/react-router": "*", + "@tanstack/react-start": ">=1.168.25", + "@types/react": "*", + "react": "*", + "rxjs": "*" + }, + "peerDependenciesMeta": { + "@angular/common": { + "optional": true + }, + "@angular/core": { + "optional": true + }, + "@angular/router": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + }, + "@tanstack/react-router": { + "optional": true + }, + "@tanstack/react-start": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "rxjs": { + "optional": true + } + } + }, "node_modules/parse-entities": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index d3aa202..bb3b206 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -43,7 +43,7 @@ "jotai": "^2.20.1", "json-edit-react": "^1.30.2", "katex": "^0.17.0", - "keycloak-js": "^26.2.4", + "oidc-spa": "^10.2.6", "leaflet": "^1.9.4", "lucide-react": "^1.22.0", "react": "^19.1.1", diff --git a/frontend/src/auth/index.ts b/frontend/src/auth/index.ts index d567caf..8c972e2 100644 --- a/frontend/src/auth/index.ts +++ b/frontend/src/auth/index.ts @@ -1,7 +1,7 @@ /*----------------------------------------------------------------------------- | Copyright (c) 2025-present, OpenTeams Inc. |----------------------------------------------------------------------------*/ -import Keycloak from 'keycloak-js'; +import { createOidc } from 'oidc-spa/core'; // Save a reference to the native fetch before it can be overridden. // @@ -42,15 +42,22 @@ export class FetchError extends Error { // Whether auth is enabled for the application. const AUTH_ENABLED = import.meta.env.VITE_AUTH_ENABLED === 'true'; -// The singleton `Keycloak` instance for handling authentication. -const keycloak = new Keycloak('/keycloak-config.json'); +// The singleton `oidc` instance for handling authentication. +let oidc: Awaited> | null = null; -// If auth is enabled, init keycloak before anything else is loaded. +// If auth is enabled, init oidc before anything else is loaded. // // This allows redirects to happen cleanly after a login and prevents // redirect loops if it were to be performed lazily in `login()`. if (AUTH_ENABLED) { - await keycloak.init({ checkLoginIframe: false }); + const configResp = await fetch('/auth-config.json'); + const config = await configResp.json(); + + oidc = await createOidc({ + issuerUri: config.issuer, + clientId: config.client_id, + BASE_URL: window.location.origin, + }); } /** @@ -66,13 +73,15 @@ export async function fetch( init: RequestInit = {}, ): Promise { // Ensure we have an unexpired token. - if (AUTH_ENABLED) { - await keycloak.updateToken(); + if (AUTH_ENABLED && oidc?.isUserLoggedIn) { + await oidc.renewTokens(); } // Create the extra headers if needed. const headers = ( - AUTH_ENABLED ? { Authorization: `Bearer ${keycloak.token ?? ''}` } : {} + AUTH_ENABLED && oidc?.isUserLoggedIn + ? { Authorization: `Bearer ${(await oidc.getTokens()).accessToken}` } + : {} ) as HeadersInit; // Clone the init object and headers to prevent snooping by the caller. @@ -91,38 +100,36 @@ export async function fetch( } /** - * A function which handles the user login via Keycloak. + * A function which handles the user login via OIDC. * * If the user is already logged-in this is a no-op. */ export async function login(): Promise { // Bail early if login is not needed. - if (!AUTH_ENABLED || keycloak.authenticated) { + if (!AUTH_ENABLED || !oidc || oidc.isUserLoggedIn) { return; } // Authenticate the user. - await keycloak.login({ redirectUri: window.location.origin }); + await oidc.login({ redirectUrl: window.location.origin }); } /** - * A function which handles user logout via Keycloack. + * A function which handles user logout via OIDC. * * If the user is already logged-out this is just a redirect to origin. */ export async function logout(): Promise { // Redirect if auth is not enabled. - // - // On execution, `keycloak.authenticated` might be `false` if the user - // is authed but the `keycloak.init()` promise has not yet resolved, - // which would yield a false negative, so don't check for it. if (!AUTH_ENABLED) { window.location.replace(window.location.origin); return; } // Log out the user. - await keycloak.logout({ redirectUri: window.location.origin }); + if (oidc?.isUserLoggedIn) { + await oidc.logout({ redirectTo: 'home' }); + } } /** @@ -145,13 +152,19 @@ export type UserProfile = { */ export function getUserProfile(): UserProfile | null { // Bail early if auth is not enabled. - if (!AUTH_ENABLED || !keycloak.authenticated) { + if (!AUTH_ENABLED || !oidc || !oidc.isUserLoggedIn) { return null; } - // Return the user profile from the parsed token data. + // Return the user profile from the decoded ID token. + const decoded = oidc.getDecodedIdToken(); + // ponytail: oidc-spa returns a generic DecodedIdToken type that extends + // the OIDC core spec with optional name/email claims. We know these are + // present if the user is logged in (they're required by the OIDC spec + // for the ID token), but the type doesn't reflect that. Cast to any + // to avoid the TS error, since the runtime invariant is sound. return { - name: keycloak.tokenParsed?.name ?? '', - email: keycloak.tokenParsed?.email ?? '', + name: (decoded as any).name ?? '', + email: (decoded as any).email ?? '', }; } diff --git a/helm/nebari-chat/config.yaml b/helm/nebari-chat/config.yaml index 0cd49f8..70075d8 100644 --- a/helm/nebari-chat/config.yaml +++ b/helm/nebari-chat/config.yaml @@ -1,6 +1,13 @@ security: authenticator: - cls_or_fn: ravnar_nebari_chat.keycloak_authenticator + cls_or_fn: _ravnar.authenticators.BearerTokenAuthenticator params: - keycloak_url: '{{ required "keycloak.url is required" .Values.keycloak.url }}' - realm: "{{ .Values.keycloak.realm }}" + token_validator: + cls_or_fn: _ravnar.authenticators.OIDCTokenValidator + params: + issuer: '{{ required "oidc.issuer is required" .Values.oidc.issuer }}' + default_permissions: + - threads:read + - threads:write + - threads:delete + - agents:read diff --git a/helm/nebari-chat/templates/frontend-configmap.yaml b/helm/nebari-chat/templates/frontend-configmap.yaml index 177993f..40311a3 100644 --- a/helm/nebari-chat/templates/frontend-configmap.yaml +++ b/helm/nebari-chat/templates/frontend-configmap.yaml @@ -8,12 +8,11 @@ metadata: labels: {{- include "ravnar.labels" (dict "top" . "component" $component) | nindent 4 }} data: - keycloak-config.json: | + auth-config.json: | {{- dict - "auth-server-url" (required "keycloak.url is required" .Values.keycloak.url) - "realm" (required "keycloak.realm is required" .Values.keycloak.realm) - "resource" (.Values.keycloak.clientId | default (printf "%s-%s-spa" .Release.Namespace (include "ravnar.component-name" (dict "top" . "component" $component)))) + "issuer" (required "oidc.issuer is required" .Values.oidc.issuer) + "client_id" (.Values.oidc.clientId | default (printf "%s-%s-spa" .Release.Namespace (include "ravnar.component-name" (dict "top" . "component" $component)))) | toPrettyJson | nindent 4 }} {{- with include "nebari-chat.ravnarContextJson" . | fromJson }} diff --git a/helm/nebari-chat/templates/frontend-deployment.yaml b/helm/nebari-chat/templates/frontend-deployment.yaml index d85aa10..20f541f 100644 --- a/helm/nebari-chat/templates/frontend-deployment.yaml +++ b/helm/nebari-chat/templates/frontend-deployment.yaml @@ -46,8 +46,8 @@ spec: key: API_URL volumeMounts: - name: config - mountPath: /usr/share/nginx/html/keycloak-config.json - subPath: keycloak-config.json + mountPath: /usr/share/nginx/html/auth-config.json + subPath: auth-config.json readOnly: true ports: - containerPort: {{ .Values.frontend.service.targetPort }} diff --git a/helm/nebari-chat/values.yaml b/helm/nebari-chat/values.yaml index 7b98bc7..4eb4065 100644 --- a/helm/nebari-chat/values.yaml +++ b/helm/nebari-chat/values.yaml @@ -7,12 +7,10 @@ config: # -- Inline configuration for the application. Merged with the default config.yaml inline: {} -keycloak: - # -- The URL of the Keycloak server - url: "" - # -- The Keycloak realm to use - realm: "nebari" - # -- The Keycloak client ID. If not set, a default is generated based on the release name +oidc: + # -- The OIDC issuer URL (e.g. https://keycloak.example.com/realms/nebari) + issuer: "" + # -- The OIDC client ID for the SPA clientId: "" ravnar: @@ -95,14 +93,6 @@ frontend: # -- The target port on the container targetPort: 8080 - keycloak: - # -- The URL of the Keycloak auth server - authServerUrl: "" - # -- The Keycloak realm for frontend authentication - realm: "nebari" - # -- The Keycloak resource/client ID for the frontend - resource: "" - api: # -- The URL of the backend API. Auto-detected if not set url: ""