Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions charts/identity-service-ui/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,21 @@ configmap:
VITE_API_URL: ""
VITE_APP_CLIENT_PORT: "5500"
VITE_APP_LOG_LEVEL: "info"
VITE_AUTH_TYPE: ""

# IAM defaults
VITE_IAM_PRODUCT_ID: ""
VITE_IAM_OIDC_CLIENT_ID: ""
VITE_IAM_UI: ""
VITE_IAM_API: ""
VITE_IAM_OIDC_ISSUER: ""
VITE_IAM_MULTI_TENANT: ""

# Secondary OIDC provider defaults
VITE_OIDC_UI: ""
VITE_OIDC_CLIENT_ID: ""
VITE_OIDC_ISSUER: ""

# Multi-tenant and authentication mode
VITE_MULTI_TENANT: ""

# Analytics and Feedback defaults
VITE_SEGMENT_ID: ""
VITE_MAZE_ID: ""
2 changes: 1 addition & 1 deletion deployments/docker/frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ RUN mkdir ./nginx/logs && \
RUN sed -i 's/<script id="vite-plugin-pwa:inline-sw">/<script id="vite-plugin-pwa:inline-sw" nonce="c28133ca-0587-459b-9d44-7015cde0ef83">/g' ./dist/index.html

# Add SSI vars
RUN sed -i 's/<head>/<head>\<script nonce="111dd4a0-4c4e-43a9-8eb4-6446ad2e10c7" language="javascript"\>window.apiUrl=`\<!--#echo var="apiUrl"--\>`;window.logLevel=`\<!--#echo var="logLevel"--\>`;window.segmentId=`\<!--#echo var="segmentId"--\>`;window.iamProductId=`\<!--#echo var="iamProductId"--\>`;window.iamUi=`\<!--#echo var="iamUi"--\>`;window.iamApi=`\<!--#echo var="iamApi"--\>`;window.iamOidcClientId=`\<!--#echo var="iamOidcClientId"--\>`;window.iamOidcIssuer=`\<!--#echo var="iamOidcIssuer"--\>`;window.oidcUi=`\<!--#echo var="oidcUi"--\>`;window.oidcClientId=`\<!--#echo var="oidcClientId"--\>`;window.oidcIssuer=`\<!--#echo var="oidcIssuer"--\>`;window.docsUrl=`\<!--#echo var="docsUrl"--\>`;window.mazeId=`\<!--#echo var="mazeId"--\>`;window.multiTenant=`\<!--#echo var="multiTenant"--\>`;window.appBaseName=`\<!--#echo var="appBaseName"--\>`;<\/script>/g' ./dist/index.html
RUN sed -i 's/<head>/<head>\<script nonce="111dd4a0-4c4e-43a9-8eb4-6446ad2e10c7" language="javascript"\>window.apiUrl=`\<!--#echo var="apiUrl"--\>`;window.logLevel=`\<!--#echo var="logLevel"--\>`;window.authType=`\<!--#echo var="authType"--\>`;window.segmentId=`\<!--#echo var="segmentId"--\>`;window.iamProductId=`\<!--#echo var="iamProductId"--\>`;window.iamUi=`\<!--#echo var="iamUi"--\>`;window.iamApi=`\<!--#echo var="iamApi"--\>`;window.iamOidcClientId=`\<!--#echo var="iamOidcClientId"--\>`;window.iamOidcIssuer=`\<!--#echo var="iamOidcIssuer"--\>`;window.oidcUi=`\<!--#echo var="oidcUi"--\>`;window.oidcClientId=`\<!--#echo var="oidcClientId"--\>`;window.oidcIssuer=`\<!--#echo var="oidcIssuer"--\>`;window.docsUrl=`\<!--#echo var="docsUrl"--\>`;window.mazeId=`\<!--#echo var="mazeId"--\>`;window.iamMultiTenant=`\<!--#echo var="iamMultiTenant"--\>`;window.appBaseName=`\<!--#echo var="appBaseName"--\>`;<\/script>/g' ./dist/index.html

# Set non root user
USER web
Expand Down
2 changes: 1 addition & 1 deletion deployments/docker/frontend/nginx/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
# SPDX-License-Identifier: Apache-2.0


envsubst '$VITE_APP_CLIENT_PORT $VITE_API_URL $VITE_APP_LOG_LEVEL $VITE_SEGMENT_ID $VITE_NODE_ENV $VITE_IAM_PRODUCT_ID $VITE_IAM_UI $VITE_IAM_API $VITE_IAM_OIDC_CLIENT_ID $VITE_IAM_OIDC_ISSUER $VITE_OIDC_UI $VITE_OIDC_CLIENT_ID $VITE_OIDC_ISSUER $VITE_MULTI_TENANT $VITE_DOCS_URL $VITE_MAZE_ID $VITE_APP_BASE_NAME' < /home/web/nginx/nginx.env.conf > /home/web/nginx/nginx.conf
envsubst '$VITE_APP_CLIENT_PORT $VITE_API_URL $VITE_APP_LOG_LEVEL $VITE_SEGMENT_ID $VITE_NODE_ENV $VITE_IAM_PRODUCT_ID $VITE_IAM_UI $VITE_IAM_API $VITE_IAM_OIDC_CLIENT_ID $VITE_IAM_OIDC_ISSUER $VITE_AUTH_TYPE $VITE_OIDC_UI $VITE_OIDC_CLIENT_ID $VITE_OIDC_ISSUER $VITE_IAM_MULTI_TENANT $VITE_DOCS_URL $VITE_MAZE_ID $VITE_APP_BASE_NAME' < /home/web/nginx/nginx.env.conf > /home/web/nginx/nginx.conf
envsubst '$VITE_OIDC_UI $VITE_API_URL' < /home/web/nginx/csp-header.env.conf > /home/web/nginx/csp-header.conf
exec "$@"
3 changes: 2 additions & 1 deletion deployments/docker/frontend/nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ http {
ssi on;
set $apiUrl "${VITE_API_URL}";
set $logLevel "${VITE_APP_LOG_LEVEL}";
set $authType "${VITE_AUTH_TYPE}";
set $segmentId "${VITE_SEGMENT_ID}";
set $iamProductId "${VITE_IAM_PRODUCT_ID}";
set $iamUi "${VITE_IAM_UI}";
Expand All @@ -113,7 +114,7 @@ http {
set $oidcUi "${VITE_OIDC_UI}";
set $oidcClientId "${VITE_OIDC_CLIENT_ID}";
set $oidcIssuer "${VITE_OIDC_ISSUER}";
set $multiTenant "${VITE_MULTI_TENANT}";
set $iamMultiTenant "${VITE_IAM_MULTI_TENANT}";
set $docsUrl "${VITE_DOCS_URL}";
set $mazeId "${VITE_MAZE_ID}";
set $appBaseName "${VITE_APP_BASE_NAME}";
Expand Down
8 changes: 6 additions & 2 deletions frontend/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ VITE_DOCS_URL=
# Example: /identity-service (for subdirectory deployment)
VITE_APP_BASE_NAME=/

# Authentication Type
# Specifies which authentication method to use
# Values: iam, oidc
VITE_AUTH_TYPE=iam

# =============================================================================
# IDENTITY AND ACCESS MANAGEMENT (IAM) CONFIGURATION
# =============================================================================
Expand Down Expand Up @@ -82,8 +87,7 @@ VITE_IAM_OIDC_ISSUER=
# - true: Uses IAM authentication with multi-tenant support
# - false: Uses secondary OIDC provider authentication
# Values: true, false
# Default: true
VITE_MULTI_TENANT=true
VITE_IAM_MULTI_TENANT=true

# =============================================================================
# SECONDARY OIDC PROVIDER CONFIGURATION (Optional)
Expand Down
31 changes: 28 additions & 3 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ Configure the following environment variables in your `.env` file:
- `VITE_APP_LOG_LEVEL` - Logging level for the application
- `VITE_DOCS_URL` - URL for application documentation
- `VITE_APP_BASE_NAME` - Base name/path for the application routing
- `VITE_MULTI_TENANT` - Enable multi-tenant support (true/false). This setting also determines the authentication mode:
- `true` - Uses IAM authentication with multi-tenant support
- `false` - Uses secondary OIDC provider authentication
- `VITE_AUTH_TYPE` - Authentication method to use (values: `iam`, `oidc`)

#### IAM Authentication

Expand All @@ -99,6 +97,7 @@ Configure the following environment variables in your `.env` file:
- `VITE_IAM_API` - IAM API service URL
- `VITE_IAM_OIDC_CLIENT_ID` - OIDC client ID for authentication
- `VITE_IAM_OIDC_ISSUER` - OIDC issuer URL
- `VITE_IAM_MULTI_TENANT` - Enable multi-tenant support (true/false)

#### Secondary OIDC Provider

Expand All @@ -111,6 +110,32 @@ Configure the following environment variables in your `.env` file:
- `VITE_SEGMENT_ID` - Segment analytics tracking ID
- `VITE_MAZE_ID` - Maze analytics tracking ID

#### Authentication Configuration

The application uses default authentication configuration options defined in `src/constants/okta.ts`. These default options apply to both IAM and OIDC authentication providers:

```typescript
export const defaultAuthConfigOptions: AuthConfigOptions = {
scopes: ['openid', 'offline_access'],
renew: 'auto',
redirectUri: `${window.location.protocol}//${window.location.host}`,
devMode: false,
renewOnTabActivation: true,
tabInactivityDuration: 1800, // 30 minutes
syncStorage: true
};
```

These options control:

- **scopes**: OAuth 2.0 scopes requested during authentication
- **renew**: Token renewal strategy ('auto' for automatic renewal)
- **redirectUri**: URI to redirect to after authentication
- **devMode**: Development mode flag for additional debugging
- **renewOnTabActivation**: Whether to renew tokens when tab becomes active
- **tabInactivityDuration**: Time in seconds before considering tab inactive
- **syncStorage**: Whether to synchronize authentication state across browser tabs

### 4. Global Configuration Setup

Configure the application's global settings by editing `src/config/global.ts`:
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/api/services/iam-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ export class IamAPIClass {
clearTokensBeforeRedirect?: boolean;
}) => void;

protected authConfig = getAuthConfig() as AuthConfigIAM;
protected authConfig = getAuthConfig() as AuthConfigIAM | undefined;

constructor() {
this.instance = axios.create({
baseURL: this.authConfig.iamApi,
baseURL: this.authConfig?.iamApi,
headers: {
'Content-Type': 'application/json'
}
Expand All @@ -59,7 +59,7 @@ export class IamAPIClass {
public getTenants = () => {
return this.instance.get<GetTenantsResponse>('/tenant', {
params: {
product: this.authConfig.productId
product: this.authConfig?.productId
}
});
};
Expand All @@ -71,7 +71,7 @@ export class IamAPIClass {
public createTenant = () => {
return this.instance.post<TenantReponse>('/tenant/user', undefined, {
params: {
product: this.authConfig.productId
product: this.authConfig?.productId
}
});
};
Expand All @@ -88,7 +88,7 @@ export class IamAPIClass {
public inviteUser = (groupId: string, data: InviteUserPayload) => {
return this.instance.post(`/user/request/invite`, data, {
params: {
product: this.authConfig.productId,
product: this.authConfig?.productId,
group: groupId
}
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/layout/tests/side-nav.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ let mockIsTbacEnabled = true;

vi.mock('@/config', () => ({
default: {
MULTI_TENANT: true,
IAM_MULTI_TENANT: true,
IAM_UI: 'https://iam.example.com',
IAM_OIDC_ISSUER: 'https://issuer.example.com',
IAM_OIDC_CLIENT_ID: 'client-id'
Expand Down
47 changes: 36 additions & 11 deletions frontend/src/config/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,28 @@
import isEnvSet from '@/utils/is-env-set';
import * as CookieConsentVanilla from 'vanilla-cookieconsent';

export enum AuthType {
IAM = 'iam',
OIDC = 'oidc'
}

declare global {
interface Window {
apiUrl?: string;
logLevel?: string;
authType?: AuthType;
iamProductId?: string;
iamUi?: string;
iamApi?: string;
iamOidcClientId?: string;
iamOidcIssuer?: string;
iamMultiTenant?: boolean;
oidcUi?: string;
oidcClientId?: string;
oidcIssuer?: string;
segmentId?: string;
docsUrl?: string;
mazeId?: string;
multiTenant?: boolean;
appBaseName?: string;
CookieConsent: typeof CookieConsentVanilla;
}
Expand All @@ -37,32 +43,56 @@ export default {
? import.meta.env.VITE_IAM_PRODUCT_ID
: typeof window !== 'undefined'
? window.iamProductId
: undefined,
: import.meta.env.MODE === 'test'
? 'test-product-id'
: undefined,
LOG_LEVEL: isEnvSet(import.meta.env.VITE_APP_LOG_LEVEL)
? import.meta.env.VITE_APP_LOG_LEVEL
: typeof window !== 'undefined'
? window.logLevel
: undefined,
AUTH_TYPE: isEnvSet(import.meta.env.VITE_AUTH_TYPE)
? (import.meta.env.VITE_AUTH_TYPE as AuthType)
: typeof window !== 'undefined'
? window.authType
: import.meta.env.MODE === 'test'
? AuthType.IAM
: undefined,
IAM_UI: isEnvSet(import.meta.env.VITE_IAM_UI)
? import.meta.env.VITE_IAM_UI
: typeof window !== 'undefined'
? window.iamUi
: undefined,
: import.meta.env.MODE === 'test'
? 'http://localhost:3000'
: undefined,
IAM_API: isEnvSet(import.meta.env.VITE_IAM_API)
? import.meta.env.VITE_IAM_API
: typeof window !== 'undefined'
? window.iamApi
: undefined,
: import.meta.env.MODE === 'test'
? 'http://localhost:8080'
: undefined,
IAM_OIDC_CLIENT_ID: isEnvSet(import.meta.env.VITE_IAM_OIDC_CLIENT_ID)
? import.meta.env.VITE_IAM_OIDC_CLIENT_ID
: typeof window !== 'undefined'
? window.iamOidcClientId
: undefined,
: import.meta.env.MODE === 'test'
? 'test-client-id'
: undefined,
IAM_OIDC_ISSUER: isEnvSet(import.meta.env.VITE_IAM_OIDC_ISSUER)
? import.meta.env.VITE_IAM_OIDC_ISSUER
: typeof window !== 'undefined'
? window.iamOidcIssuer
: undefined,
: import.meta.env.MODE === 'test'
? 'http://localhost:8080/oauth2/default'
: undefined,
IAM_MULTI_TENANT: isEnvSet(import.meta.env.VITE_IAM_MULTI_TENANT)
? import.meta.env.VITE_IAM_MULTI_TENANT === 'true'
: typeof window !== 'undefined'
? window.iamMultiTenant
: import.meta.env.MODE === 'test'
? true
: undefined,
OIDC_UI: isEnvSet(import.meta.env.VITE_OIDC_UI)
? import.meta.env.VITE_OIDC_UI
: typeof window !== 'undefined'
Expand Down Expand Up @@ -93,11 +123,6 @@ export default {
: typeof window !== 'undefined'
? window.mazeId
: undefined,
MULTI_TENANT: isEnvSet(import.meta.env.VITE_MULTI_TENANT)
? import.meta.env.VITE_MULTI_TENANT === 'true'
: typeof window !== 'undefined'
? (window.multiTenant ?? true)
: true,
APP_BASE_NAME: isEnvSet(import.meta.env.VITE_APP_BASE_NAME)
? import.meta.env.VITE_APP_BASE_NAME
: typeof window !== 'undefined'
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/constants/okta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {AuthConfigOptions} from '@/types/okta';
export const defaultAuthConfigOptions: AuthConfigOptions = {
scopes: ['openid', 'offline_access'],
renew: 'auto',
redirectUri: `${window.location.protocol}//${window.location.host}/`,
redirectUri: `${window.location.protocol}//${window.location.host}`,
devMode: false,
renewOnTabActivation: true,
tabInactivityDuration: 1800, // 30 minutes
Expand Down
18 changes: 9 additions & 9 deletions frontend/src/hooks/use-auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {isMultiTenant} from '@/utils/get-auth-config';
import {useAuthIAM} from '@/providers/auth-provider/iam/use-auth-iam';
import {useAuthOIDC} from '@/providers/auth-provider/oicd/use-auth-oidc';
import {AuthContextIAM, AuthContextOIDC} from '@/types/okta';
import config, {AuthType} from '@/config';

export const useAuth = (): AuthContextIAM | AuthContextOIDC => {
const multiTenant = isMultiTenant();
let auth: typeof useAuthIAM | typeof useAuthOIDC = useAuthOIDC;

switch (multiTenant) {
case true:
auth = useAuthIAM;
break;
case false:
auth = useAuthOIDC;
break;
if (!config.AUTH_TYPE) {
console.warn('No AUTH_TYPE configured...');
} else if (config.AUTH_TYPE === AuthType.IAM) {
auth = useAuthIAM;
} else if (config.AUTH_TYPE === AuthType.OIDC) {
auth = useAuthOIDC;
} else {
console.warn(`Unknown AUTH_TYPE configured: ${config.AUTH_TYPE}`);
}

return {...auth()};
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/settings/base/settings-base.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import SettingsBase from './settings-base';
// Update the mock to use MULTI_TENANT instead of IAM_MULTI_TENANT
vi.mock('@/config', () => ({
default: {
MULTI_TENANT: true,
IAM_MULTI_TENANT: true,
IAM_UI: 'https://iam.example.com',
IAM_OIDC_ISSUER: 'https://issuer.example.com',
IAM_OIDC_CLIENT_ID: 'client-id'
Expand Down
15 changes: 9 additions & 6 deletions frontend/src/providers/auth-provider/auth-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {isMultiTenant} from '@/utils/get-auth-config';
import AuthProviderIAM from './iam/auth-provider-iam';
import AuthProviderOIDC from './oicd/auth-provider-oidc';
import config, {AuthType} from '@/config';
import {AuthError} from '@/components/router/auth-error';

const AuthProvider: React.FC<React.PropsWithChildren> = ({children}) => {
const isMultiTenantResult = isMultiTenant();

if (isMultiTenantResult) {
if (!config.AUTH_TYPE) {
return <AuthError error={new Error('No AUTH_TYPE configured')} />;
} else if (config.AUTH_TYPE === AuthType.IAM) {
return <AuthProviderIAM>{children}</AuthProviderIAM>;
} else if (config.AUTH_TYPE === AuthType.OIDC) {
return <AuthProviderOIDC>{children}</AuthProviderOIDC>;
} else {
return <AuthError error={new Error(`Unknown AUTH_TYPE configured: ${config.AUTH_TYPE}`)} />;
}

return <AuthProviderOIDC>{children}</AuthProviderOIDC>;
};

export default AuthProvider;
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ const AuthProviderIAM: React.FC<React.PropsWithChildren> = ({children}) => {

const authConfig: AuthConfigIAM = useMemo(() => {
return {
...(getAuthConfig() as AuthConfigIAM),
configOptions: {
redirectUri: `${window.location.protocol}//${window.location.host}`
}
...(getAuthConfig() as AuthConfigIAM)
};
}, []);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ const AuthProviderOIDC: React.FC<React.PropsWithChildren> = ({children}) => {

const authConfig: AuthConfigOIDC = React.useMemo(() => {
return {
...(getAuthConfig() as AuthConfigOIDC),
configOptions: {
redirectUri: `${window.location.protocol}//${window.location.host}`
}
...(getAuthConfig() as AuthConfigOIDC)
};
}, []);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import React from 'react';
// Mock the config
vi.mock('@/config', () => ({
default: {
MULTI_TENANT: true,
IAM_MULTI_TENANT: true,
IAM_UI: 'https://iam.example.com',
IAM_OIDC_ISSUER: 'https://issuer.example.com',
IAM_OIDC_CLIENT_ID: 'client-id'
Expand Down
Loading
Loading