Skip to content

Commit ab9e350

Browse files
committed
Add configuration support and environment variables for Thunder Gate App
- Introduced .env.example for environment variable configuration. - Updated README.md to include configuration instructions. - Modified server.js to support dynamic PORT and HOST from environment variables. - Added app.config.ts for application configuration using environment variables. - Refactored imports in layout.tsx and content.tsx to use app.config.ts.
1 parent 0fa996d commit ab9e350

6 files changed

Lines changed: 131 additions & 21 deletions

File tree

frontend/apps/gate/.env.example

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Thunder Gate App Configuration
2+
# Copy this file to .env.local for local development
3+
# or set these environment variables in your deployment environment
4+
5+
# Product name displayed in the UI
6+
NEXT_PUBLIC_PRODUCT_NAME=WSO2 Thunder
7+
8+
# Thunder backend host (defaults to https://localhost:8090 if not set)
9+
NEXT_PUBLIC_THUNDER_HOST=https://localhost:8090
10+
11+
# Backend API endpoints (will use THUNDER_HOST if not explicitly set)
12+
# NEXT_PUBLIC_FLOW_EXECUTION_ENDPOINT=https://localhost:8090/flow/execute
13+
# NEXT_PUBLIC_AUTHORIZATION_ENDPOINT=https://localhost:8090/oauth2/authorize
14+
15+
# Run the server with HTTPS. Default's to true if not defined.
16+
ENABLE_HTTPS=true

frontend/apps/gate/README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Thunder - Gate App
22

3-
This is the gate app for project thunder. Which serves UIs for Login, Registration and Recovery.
3+
This is the gate app for project thunder. Which serves UIs for Login, Registration and Recovery.
44

55
### ✅ Prerequisites
66

@@ -26,3 +26,24 @@ openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.cert -days 365
2626
```bash
2727
pnpm --filter gate dev
2828
```
29+
30+
### ⚙️ Step 4: Configuration
31+
32+
The application supports environment variables for configuration that can be changed after build time.
33+
34+
#### Environment Variables
35+
36+
Copy `.env.example` to `.env.local` for local development:
37+
38+
```bash
39+
cp .env.example .env.local
40+
```
41+
42+
Available environment variables:
43+
44+
- `NEXT_PUBLIC_PRODUCT_NAME`: Product name displayed in the UI (default: "WSO2 Thunder")
45+
- `NEXT_PUBLIC_THUNDER_HOST`: Thunder backend host URL (default: `https://localhost:8090`)
46+
- `NEXT_PUBLIC_FLOW_EXECUTION_ENDPOINT`: Backend flow execution API endpoint (defaults to `{THUNDER_HOST}/flow/execute`)
47+
- `NEXT_PUBLIC_AUTHORIZATION_ENDPOINT`: Backend authorization API endpoint (defaults to `{THUNDER_HOST}/oauth2/authorize`)
48+
49+
**Note**: If you set `NEXT_PUBLIC_THUNDER_HOST`, you don't need to set the individual endpoint URLs unless you want to override them specifically.

frontend/apps/gate/server.js

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import fs from 'fs';
2020
import path from 'path';
2121
import https from 'https';
22+
import http from 'http';
2223
import { fileURLToPath, parse } from 'url';
2324
import next from 'next';
2425

@@ -35,31 +36,50 @@ if (fs.existsSync(requiredServerFilesConfig)) {
3536
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig);
3637
}
3738

38-
const PORT = 9090;
39-
const HOST = 'localhost';
39+
const PORT = process.env.PORT || 9090;
40+
const HOST = process.env.HOST || 'localhost';
41+
const ENABLE_HTTPS = process.env.ENABLE_HTTPS !== 'false';
4042
const keyPath = path.resolve(__dirname, 'server.key');
4143
const certPath = path.resolve(__dirname, 'server.cert');
4244
const dev = process.env.NODE_ENV === 'development';
4345
const app = next({ dev: dev, dir: __dirname });
44-
const httpsOptions = {
45-
key: fs.readFileSync(keyPath),
46-
cert: fs.readFileSync(certPath),
47-
};
46+
47+
// HTTPS options - only used if ENABLE_HTTPS is true
48+
let httpsOptions = null;
49+
if (ENABLE_HTTPS) {
50+
try {
51+
httpsOptions = {
52+
key: fs.readFileSync(keyPath),
53+
cert: fs.readFileSync(certPath),
54+
};
55+
} catch (error) {
56+
console.error(`Failed to load SSL certificates: ${error.message}`);
57+
console.error('Either provide valid certificates or set ENABLE_HTTPS=false');
58+
process.exit(1);
59+
}
60+
}
4861

4962
const handle = app.getRequestHandler();
5063

5164
function getTimestampWithOffset() {
5265
const now = new Date();
5366

54-
const pad = (n) => n.toString().padStart(2, '0');
67+
const pad = n => n.toString().padStart(2, '0');
5568

56-
const isoDate = now.getFullYear() + '-' +
57-
pad(now.getMonth() + 1) + '-' +
58-
pad(now.getDate()) + 'T' +
59-
pad(now.getHours()) + ':' +
60-
pad(now.getMinutes()) + ':' +
61-
pad(now.getSeconds()) + '.' +
62-
now.getMilliseconds().toString().padStart(3, '0');
69+
const isoDate =
70+
now.getFullYear() +
71+
'-' +
72+
pad(now.getMonth() + 1) +
73+
'-' +
74+
pad(now.getDate()) +
75+
'T' +
76+
pad(now.getHours()) +
77+
':' +
78+
pad(now.getMinutes()) +
79+
':' +
80+
pad(now.getSeconds()) +
81+
'.' +
82+
now.getMilliseconds().toString().padStart(3, '0');
6383

6484
const offsetMin = now.getTimezoneOffset();
6585
const offsetSign = offsetMin <= 0 ? '+' : '-';
@@ -70,16 +90,28 @@ function getTimestampWithOffset() {
7090
return `${isoDate}${tzOffset}`;
7191
}
7292

73-
console.log(`Starting WSO2 Thunder gate app in ${dev ? 'development' : 'production'} mode...`);
93+
console.log(
94+
`Starting WSO2 Thunder gate app in ${dev ? 'development' : 'production'} mode with ${ENABLE_HTTPS ? 'HTTPS' : 'HTTP'}...`,
95+
);
7496

7597
app.prepare().then(() => {
76-
https.createServer(httpsOptions, (req, res) => {
98+
const requestHandler = (req, res) => {
7799
const parsedUrl = parse(req.url, true);
78100
handle(req, res, parsedUrl);
79-
}).listen(PORT, () => {
101+
};
102+
103+
let server;
104+
if (ENABLE_HTTPS && httpsOptions) {
105+
server = https.createServer(httpsOptions, requestHandler);
106+
} else {
107+
server = http.createServer(requestHandler);
108+
}
109+
110+
server.listen(PORT, HOST, () => {
80111
const isoWithOffset = getTimestampWithOffset();
112+
const protocol = ENABLE_HTTPS ? 'https' : 'http';
81113
console.log(
82-
`time=${isoWithOffset} level=INFO msg="WSO2 Thunder gate app started..." address=${HOST}:${PORT}`
114+
`time=${isoWithOffset} level=INFO msg="WSO2 Thunder gate app started..." address=${protocol}://${HOST}:${PORT}`,
83115
);
84116
});
85117
});

frontend/apps/gate/src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import ThemeToggle from '@oxygen-ui/react/src/components/ThemeToggle/ThemeToggle
2121
import Grid from '@oxygen-ui/react/src/components/Grid/Grid';
2222
import Paper from '@oxygen-ui/react/src/components/Paper/Paper';
2323
import Typography from '@oxygen-ui/react/src/components/Typography/Typography';
24-
import AppConfig from '@/configs/app.json';
24+
import AppConfig from '@/configs/app.config';
2525
import BaseLayout from '@/layouts/base';
2626
import SideImage from '@/images/layout-image';
2727
import type { Metadata } from 'next';

frontend/apps/gate/src/app/login/content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import InputLabel from '@oxygen-ui/react/src/components/InputLabel/InputLabel';
2626
import Typography from '@oxygen-ui/react/src/components/Typography/Typography';
2727
import React, { useState, useEffect, ReactElement } from 'react';
2828
import axios from 'axios';
29-
import AppConfig from '@/configs/app.json';
29+
import AppConfig from '@/configs/app.config';
3030

3131
interface LoginInput {
3232
name: string;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
import AppConfigDefaults from './app.json';
20+
21+
interface AppConfig {
22+
productName: string;
23+
flowExecutionEndpoint: string;
24+
authorizationEndpoint: string;
25+
}
26+
27+
/**
28+
* Application configuration that uses environment variables with fallbacks to JSON defaults.
29+
* Environment variables take precedence over JSON values when available.
30+
*/
31+
const getThunderHost = (): string => {
32+
return process.env.NEXT_PUBLIC_THUNDER_HOST || 'https://localhost:8090';
33+
};
34+
35+
export const AppConfig: AppConfig = {
36+
productName: process.env.NEXT_PUBLIC_PRODUCT_NAME || AppConfigDefaults.productName,
37+
flowExecutionEndpoint: process.env.NEXT_PUBLIC_FLOW_EXECUTION_ENDPOINT || `${getThunderHost()}/flow/execute`,
38+
authorizationEndpoint: process.env.NEXT_PUBLIC_AUTHORIZATION_ENDPOINT || `${getThunderHost()}/oauth2/authorize`,
39+
};
40+
41+
export default AppConfig;

0 commit comments

Comments
 (0)