Tenant-specific OIDC: separate Zitadel projects per tenant
Each tenant config now includes oidcClientId. Auth composable reads client ID from tenant config instead of hardcoded fallback. Dev tenant uses restricted Zitadel project (role-check enabled, developer grant). Added NODE_ENV=production to env files to fix --mode dev builds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
42c6079755
commit
d6337c1ece
@ -1 +1,2 @@
|
|||||||
|
NODE_ENV=production
|
||||||
VITE_TENANT=loop42
|
VITE_TENANT=loop42
|
||||||
|
|||||||
@ -12,14 +12,15 @@
|
|||||||
import { ref, computed, type Ref } from 'vue';
|
import { ref, computed, type Ref } from 'vue';
|
||||||
import router from '../router';
|
import router from '../router';
|
||||||
import { getApiBase } from '../utils/apiBase';
|
import { getApiBase } from '../utils/apiBase';
|
||||||
|
import tenant from '../tenant';
|
||||||
|
|
||||||
const TOKEN_KEY = 'nyx_session';
|
const TOKEN_KEY = 'nyx_session';
|
||||||
const VERIFIER_KEY = 'pkce_verifier';
|
const VERIFIER_KEY = 'pkce_verifier';
|
||||||
const RETURN_KEY = 'auth_return_path';
|
const RETURN_KEY = 'auth_return_path';
|
||||||
|
|
||||||
// Zitadel config — fetched from backend or hardcoded fallback
|
// Zitadel config — tenant-specific client ID, fetched from backend as override
|
||||||
let _issuer = 'https://auth.loop42.de';
|
let _issuer = 'https://auth.loop42.de';
|
||||||
let _clientId = '365996029172056091';
|
let _clientId = tenant.oidcClientId;
|
||||||
const _redirectUri = `${window.location.origin}/login`;
|
const _redirectUri = `${window.location.origin}/login`;
|
||||||
const _scopes = 'openid profile email';
|
const _scopes = 'openid profile email';
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,7 @@
|
|||||||
* tenant.ts — Build-time tenant configuration
|
* tenant.ts — Build-time tenant configuration
|
||||||
*
|
*
|
||||||
* VITE_TENANT selects which tenant config to load.
|
* VITE_TENANT selects which tenant config to load.
|
||||||
* Vite's static analysis + tree-shaking ensures only the
|
* Direct dynamic import ensures only the active tenant is bundled.
|
||||||
* active tenant's code ends up in the bundle.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface TenantFeatures {
|
export interface TenantFeatures {
|
||||||
@ -18,17 +17,21 @@ export interface TenantConfig {
|
|||||||
name: string;
|
name: string;
|
||||||
domain: string;
|
domain: string;
|
||||||
defaultTheme: string;
|
defaultTheme: string;
|
||||||
|
oidcClientId: string;
|
||||||
features: TenantFeatures;
|
features: TenantFeatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
const modules = import.meta.glob('../tenants/*/config.ts', { eager: true, import: 'default' });
|
// Vite replaces import.meta.env.VITE_TENANT at build time,
|
||||||
|
// making the import path a string literal → only one tenant bundled.
|
||||||
|
const modules: Record<string, { default: TenantConfig }> = import.meta.glob('../tenants/*/config.ts', { eager: true });
|
||||||
|
|
||||||
const tenantId = import.meta.env.VITE_TENANT || 'loop42';
|
const tenantId = import.meta.env.VITE_TENANT || 'loop42';
|
||||||
const key = `../tenants/${tenantId}/config.ts`;
|
const key = `../tenants/${tenantId}/config.ts`;
|
||||||
const config = modules[key] as TenantConfig;
|
const mod = modules[key];
|
||||||
|
|
||||||
if (!config) {
|
if (!mod) {
|
||||||
throw new Error(`Unknown tenant: ${tenantId}. Available: ${Object.keys(modules).join(', ')}`);
|
throw new Error(`Unknown tenant: ${tenantId}. Available: ${Object.keys(modules).join(', ')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const config: TenantConfig = mod.default;
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ const config: TenantConfig = {
|
|||||||
name: 'loop42 Dev',
|
name: 'loop42 Dev',
|
||||||
domain: 'loop42.dev',
|
domain: 'loop42.dev',
|
||||||
defaultTheme: 'titan',
|
defaultTheme: 'titan',
|
||||||
|
oidcClientId: '366683272559788059',
|
||||||
features: {
|
features: {
|
||||||
graph: true,
|
graph: true,
|
||||||
trace: true,
|
trace: true,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ const config: TenantConfig = {
|
|||||||
name: 'loop42',
|
name: 'loop42',
|
||||||
domain: 'loop42.de',
|
domain: 'loop42.de',
|
||||||
defaultTheme: 'loop42',
|
defaultTheme: 'loop42',
|
||||||
|
oidcClientId: '365996029172056091',
|
||||||
features: {
|
features: {
|
||||||
graph: false,
|
graph: false,
|
||||||
trace: false,
|
trace: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user