Skip to content

Commit f8c6f60

Browse files
tomski747orius123omercnet
authored
Runtime env var support (#701)
* WIP * WIP * M * Everything works * Fix yarn.lock * Fix package.json * No need for react-inject-env anymore * Fix some tests * Fix * NOT WIP * Cleanup a bit * Fix logger * Revert * Fix template test * Node 20 * Fix eslintrc.json * nvmrc * Sanitize URL * Fix tests * Sanitize? * Fix problems * Clean yarn.lock * Revert package.json * Fedramp improvments * Add DESCOPE to env filter * Oopsy * Allow branch name in image tag for fedramp * Use Caddy * Match to the old server * Clean * Debug * Works dont touch * Update Dockerfile Co-authored-by: Omer Cohen <[email protected]> * WIP * Fix Caddyfile * Cleaner and better * Works as http docker * Added documentation * Cleanup * Support legacy env var names --------- Co-authored-by: tomski747 <[email protected]> Co-authored-by: Eliya Sadan <[email protected]> Co-authored-by: Omer Cohen <[email protected]>
1 parent 5e8a351 commit f8c6f60

14 files changed

+361
-153
lines changed

.dockerignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
.git
3+

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,5 @@ yarn-error.log*
3131
.vercel
3232
.env
3333
.bom
34+
35+
tmp*

.husky/pre-commit

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11

2+
. "$(dirname "$0")/_/husky.sh"
23
yarn run format-lint

Caddyfile

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
debug
3+
log {
4+
format console
5+
output stdout
6+
level info
7+
}
8+
}
9+
10+
http://*:{$PORT:8080} {
11+
log
12+
encode gzip
13+
14+
handle /login* {
15+
uri strip_prefix /login
16+
root * {$WWW_ROOT:/www}
17+
try_files {path} /index.html
18+
file_server browse
19+
}
20+
21+
vars {
22+
REACT_APP_DESCOPE_BASE_URL '{$REACT_APP_DESCOPE_BASE_URL:https://api.descope.com}'
23+
REACT_APP_CONTENT_BASE_URL '{$REACT_APP_CONTENT_BASE_URL:https://api.descope.com/pages}'
24+
REACT_APP_USE_ORIGIN_BASE_URL '{$REACT_APP_USE_ORIGIN_BASE_URL:false}'
25+
REACT_APP_FAVICON_URL_TEMPLATE '{$REACT_APP_FAVICON_URL_TEMPLATE:https://api.descope.com/pages/\{projectId}}/v2-beta/\{ssoAppId}/assets/favicon.ico'
26+
REACT_APP_DEFAULT_FAVICON_URL '{$REACT_APP_DEFAULT_FAVICON_URL:https://imgs.descope.com/auth-hosting/favicon.svg}'
27+
DESCOPE_PROJECT_ID '{$DESCOPE_PROJECT_ID}'
28+
DESCOPE_FLOW_ID '{$DESCOPE_FLOW_ID}'
29+
LOGGER '{$LOGGER:false}'
30+
}
31+
32+
handle /login/env.js {
33+
uri strip_prefix /login
34+
templates
35+
respond `
36+
window.env = {
37+
REACT_APP_DESCOPE_BASE_URL: {{ placeholder "http.vars.REACT_APP_DESCOPE_BASE_URL" }},
38+
REACT_APP_CONTENT_BASE_URL: {{ placeholder "http.vars.REACT_APP_CONTENT_BASE_URL" }},
39+
REACT_APP_USE_ORIGIN_BASE_URL: {{ placeholder "http.vars.REACT_APP_USE_ORIGIN_BASE_URL" }},
40+
REACT_APP_FAVICON_URL_TEMPLATE: {{ placeholder "http.vars.REACT_APP_FAVICON_URL_TEMPLATE" }},
41+
REACT_APP_DEFAULT_FAVICON_URL: {{ placeholder "http.vars.REACT_APP_DEFAULT_FAVICON_URL" }},
42+
DESCOPE_PROJECT_ID: {{ placeholder "http.vars.DESCOPE_PROJECT_ID" }},
43+
DESCOPE_FLOW_ID: {{ placeholder "http.vars.DESCOPE_FLOW_ID" }},
44+
LOGGER: {{ placeholder "http.vars.LOGGER" }}
45+
};`
46+
}
47+
48+
# Optional: Redirect root to /login
49+
handle {
50+
redir / /login permanent
51+
}
52+
}
53+
54+
*:{$METRICS_PORT:2000} {
55+
log
56+
metrics {$METRICS_PATH:/metrics}
57+
}

Dockerfile

+20-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# syntax=docker/dockerfile:1@sha256:93bfd3b68c109427185cd78b4779fc82b484b0b7618e36d0f104d4d801e66d25
22
ARG NODE_VERSION=18
3+
ARG HTML_DIR=/usr/share/nginx/html
4+
ARG REACT_APP_DESCOPE_BASE_URL="https://api.descope.com"
5+
ARG REACT_APP_CONTENT_BASE_URL="https://static.descope.com/pages"
6+
ARG REACT_APP_USE_ORIGIN_BASE_URL="false"
7+
ARG REACT_APP_FAVICON_URL="https://imgs.descope.com/auth-hosting/favicon.svg"
8+
ARG DESCOPE_PROJECT_ID=""
9+
ARG DESCOPE_FLOW_ID=""
310

411
ARG BUILDPLATFORM
512
FROM --platform=${BUILDPLATFORM} node:${NODE_VERSION}-alpine as builder
@@ -10,37 +17,24 @@ COPY ["package.json", "yarn.lock*", "./"]
1017

1118
RUN yarn install --production=false
1219
COPY . .
13-
ARG REACT_APP_DESCOPE_BASE_URL=""
14-
ARG REACT_APP_CONTENT_BASE_URL=""
15-
ARG REACT_APP_USE_ORIGIN_BASE_URL="true"
20+
1621
RUN yarn build
1722

18-
FROM nginx:alpine@sha256:814a8e88df978ade80e584cc5b333144b9372a8e3c98872d07137dbf3b44d0e4
23+
FROM ghcr.io/descope/caddy:v0.0.4
1924

20-
RUN apk add openssl && \
21-
openssl req -x509 -nodes -days 365 -subj "/C=CA/ST=QC/O=Company, Inc./CN=mydomain.com" -addext "subjectAltName=DNS:mydomain.com" -newkey rsa:2048 -keyout /etc/ssl/private/nginx-selfsigned.key -out /etc/ssl/certs/nginx-selfsigned.crt;
25+
ENV PORT=8080
26+
ENV WWW_ROOT=/www
27+
ENV XDG_DATA_HOME=/tmp
28+
ENV XDG_CONFIG_HOME=/tmp
29+
ENV XDG_CACHE_HOME=/tmp
2230

23-
RUN cat > /etc/nginx/conf.d/default.conf <<EOF
24-
server {
25-
listen 80;
26-
listen 443 ssl http2 default_server;
27-
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
28-
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
29-
server_name localhost;
31+
WORKDIR ${WWW_ROOT}
3032

31-
rewrite ^/login/(.*)$ /$1 last;
33+
COPY --from=builder --chown=1000:1000 /app/build ${WWW_ROOT}
34+
COPY --from=builder --chown=1000:1000 /app/package.json ${WWW_ROOT}
3235

33-
location / {
34-
root /usr/share/nginx/html;
35-
index index.html;
36-
try_files \$uri \$uri/ /index.html; # this ensures react routing works
37-
}
38-
}
39-
EOF
36+
ADD --chown=nonroot:nonroot Caddyfile /etc/caddy/Caddyfile
4037

41-
EXPOSE 80 443
42-
WORKDIR /usr/share/nginx/html
43-
RUN rm -rf ./*
44-
COPY --from=builder /app/build ./
38+
RUN caddy validate --config /etc/caddy/Caddyfile
4539

46-
ENTRYPOINT ["nginx", "-g", "daemon off;"]
40+
CMD ["run", "--config", "/etc/caddy/Caddyfile"]

README.md

+37-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ This is a React web application that runs Descope's login flows according to the
66

77
### Deployment
88

9-
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fdescope%2Fauth-hosting&env=DESCOPE_PROJECT_ID&demo-title=Descope%20Hosted%20Auth%20Page&demo-description=https%3A%2F%2Fgithub.com%2Fdescope%2Fauth-hosting%2F%23readme&demo-url=https%3A%2F%2Fauth.descope.io%2F)
9+
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fdescope%2Fauth-hosting&env=DESCOPE_PROJECT_ID&demo-title=Descope%20Hosted%20Auth%20Page&demo-description=https%3A%2F%2Fgithub.com%2Fdescope%2Fauth-hosting%2F%23readme&demo-url=https%3A%2F%2Fapi.descope.com%2Flogin)
1010

11-
By default, the app is deployed to the Descope hosting page in [https://auth.descope.io](https://auth.descope.io).
11+
By default, the app is deployed to the Descope hosting page in [https://api.descope.com/login](https://api.descope.com/login).
1212
The main purpose is to allow easy integration for descopers implementing authentication with Descope (such as OIDC [use case](#open-id-connect-oidc-use-cases-in-descope)).
1313

1414
In case you want to have your own hosted page (customize styling, your own domain, etc.), you can use this repository as a template, do the relevant modification and host it (using Vercel, etc.)
@@ -65,3 +65,38 @@ These are the different query parameters you can use:
6565
In case you don't want to provide the project ID as part of the URL, you can specify it as an environment variable `DESCOPE_PROJECT_ID`.
6666
You can use `.env` file for that.
6767
From the project root directory run: `cp .env.example .env`, and set your Descope Project and flow IDs.
68+
69+
**Using docker**
70+
71+
In case you want to use the docker version these are the steps:
72+
73+
1. Build (Official hosted docker image is comming soon)
74+
75+
```(bash)
76+
# Optional build-args: (ex - using custom API host or pinning the project id)
77+
docker build
78+
--build-arg REACT_APP_DESCOPE_BASE_URL="https://api.descope.com"
79+
--build-arg REACT_APP_CONTENT_BASE_URL="https://static.descope.com/pages"
80+
--build-arg REACT_APP_USE_ORIGIN_BASE_URL="false"
81+
--build-arg REACT_APP_FAVICON_URL="https://imgs.descope.com/auth-hosting/favicon.svg"
82+
--build-arg DESCOPE_PROJECT_ID=""
83+
--build-arg DESCOPE_FLOW_ID=""
84+
--tag my-registry.com/descope/auth-hosting
85+
--push
86+
.
87+
```
88+
89+
2. Run
90+
91+
```(bash)
92+
docker run -p 8080:8080 auth-hosting
93+
# (optional) the build-args are available also during run-time as env vars:
94+
docker run -p 8080:8080
95+
-e REACT_APP_DESCOPE_BASE_URL="https://api.descope.com"
96+
-e REACT_APP_CONTENT_BASE_URL="https://static.descope.com/pages"
97+
-e REACT_APP_USE_ORIGIN_BASE_URL="false"
98+
-e REACT_APP_FAVICON_URL="https://imgs.descope.com/auth-hosting/favicon.svg"
99+
-e DESCOPE_PROJECT_ID=""
100+
-e DESCOPE_FLOW_ID=""
101+
my-registry.com/descope/auth-hosting
102+
```

api/favicon.js

-16
This file was deleted.

config-overrides.js

+67-20
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,71 @@ const gitSha =
66
process.env.GITHUB_SHA ??
77
process.env.GIT_SHA;
88

9-
module.exports = function override(config, env) {
10-
// New config, e.g. config.plugins.push...
11-
delete config.module.rules[1].oneOf[3].include;
12-
13-
// Add a hook to write the version file after build
14-
config.plugins.push({
15-
apply: (compiler) => {
16-
compiler.hooks.afterEmit.tap('CreateVersionFile', (compilation) => {
17-
const versionPath = path.join(compiler.options.output.path, 'version');
18-
19-
try {
20-
fs.writeFileSync(versionPath, gitSha);
21-
} catch (error) {
22-
console.error('Error writing version file:', error);
23-
}
24-
});
25-
}
26-
});
27-
28-
return config;
9+
module.exports = {
10+
// The Webpack config to use when compiling your react app for development or production.
11+
webpack: function (config, env) {
12+
// New config, e.g. config.plugins.push...
13+
delete config.module.rules[1].oneOf[3].include;
14+
15+
// Add a hook to write the version file after build
16+
config.plugins.push({
17+
apply: (compiler) => {
18+
compiler.hooks.afterEmit.tap('CreateVersionFile', (compilation) => {
19+
const versionPath = path.join(
20+
compiler.options.output.path,
21+
'version'
22+
);
23+
24+
try {
25+
fs.writeFileSync(versionPath, gitSha ?? env);
26+
} catch (error) {
27+
console.error('Error writing version file:', error);
28+
}
29+
});
30+
31+
compiler.hooks.afterEmit.tap('GenerateEnvJS', (compilation) => {
32+
const envPath = path.join(compiler.options.output.path, 'env.js');
33+
34+
try {
35+
// Filter out any keys that start with 'npm_'
36+
const filteredEnv = Object.fromEntries(
37+
Object.entries(process.env).filter(
38+
([key]) =>
39+
key.startsWith('REACT_APP') ||
40+
key.startsWith('NEXT_PUBLIC') ||
41+
key.startsWith('PUBLIC_URL')
42+
)
43+
);
44+
45+
fs.writeFileSync(
46+
envPath,
47+
`window.env = ${JSON.stringify(filteredEnv)}`
48+
);
49+
} catch (error) {
50+
console.error('Error writing env file:', error);
51+
}
52+
});
53+
}
54+
});
55+
return config;
56+
},
57+
devServer: function (configFunction) {
58+
return function (proxy, allowedHost) {
59+
const config = configFunction(proxy, allowedHost);
60+
61+
// Configure dev server to serve env.js
62+
config.devMiddleware = {
63+
writeToDisk: true
64+
};
65+
66+
// Add static serving configuration
67+
config.static = {
68+
directory: path.join(__dirname, 'build'),
69+
publicPath: process.env.PUBLIC_URL ?? '/login',
70+
watch: true
71+
};
72+
73+
return config;
74+
};
75+
}
2976
};

public/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<link rel="icon" href="%PUBLIC_URL%/favicon.svg" />
99
<meta name="viewport" content="width=device-width, initial-scale=1" />
1010
<meta name="theme-color" content="#000000" />
11+
<script src="%PUBLIC_URL%/env.js"></script>
1112
</head>
1213
<body>
1314
<noscript>You need to enable JavaScript to run this app.</noscript>

0 commit comments

Comments
 (0)