Skip to content
This repository was archived by the owner on May 26, 2023. It is now read-only.

Commit 550b487

Browse files
authored
Support oauth to remote decoder via web oidc token. (#445)
* Support oauth to remote decoder via web oidc token. * Improve terminology and refer to Codec not Remote Encoder.
1 parent f04ba51 commit 550b487

File tree

6 files changed

+62
-47
lines changed

6 files changed

+62
-47
lines changed

README.md

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,21 @@ For a **video demo** of how this looks, you can [check our docs](https://docs.te
2020

2121
Set these environment variables if you need to change their defaults
2222

23-
| Variable | Description | Default |
24-
| ----------------------------- | ----------------------------------------------------------------- | ----------------------------- |
25-
| TEMPORAL_GRPC_ENDPOINT | String representing server gRPC endpoint | 127.0.0.1:7233 |
26-
| TEMPORAL_WEB_PORT | HTTP port to serve on | 8088 |
27-
| TEMPORAL_CONFIG_PATH | Path to config file, see [configurations](#configuring-authentication-optional) | ./server/config.yml |
28-
| TEMPORAL_PERMIT_WRITE_API | Boolean to permit write API methods such as Terminating Workflows | true |
29-
| TEMPORAL_WEB_ROOT_PATH | The root path to serve the app under. Ex. "/test/" | / |
30-
| TEMPORAL_HOT_RELOAD_PORT | HTTP port used by hot reloading in development | 8081 |
31-
| TEMPORAL_HOT_RELOAD_TEST_PORT | HTTP port used by hot reloading in tests | 8082 |
32-
| TEMPORAL_SESSION_SECRET | Secret used to hash the session with HMAC | "ensure secret in production" |
33-
| TEMPORAL_EXTERNAL_SCRIPTS | Additional JavaScript tags to serve in the UI | |
34-
| TEMPORAL_GRPC_MAX_MESSAGE_LENGTH | gRPC max message length (bytes) | 4194304 (4mb) |
35-
| TEMPORAL_DATA_ENCODER_ENDPOINT | Remote Data Encoder Endpoint, explained below | |
23+
| Variable | Description | Default |
24+
| -------------------------------- | ----------------------------------------------------------------- | ----------------------------- |
25+
| TEMPORAL_GRPC_ENDPOINT | String representing server gRPC endpoint | 127.0.0.1:7233 |
26+
| TEMPORAL_WEB_PORT | HTTP port to serve on | 8088 |
27+
| TEMPORAL_CONFIG_PATH | Path to config file, see [configurations](#configuring-authentication-optional) | ./server/config.yml |
28+
| TEMPORAL_PERMIT_WRITE_API | Boolean to permit write API methods such as Terminating Workflows | true |
29+
| TEMPORAL_WEB_ROOT_PATH | The root path to serve the app under. Ex. "/test/" | / |
30+
| TEMPORAL_HOT_RELOAD_PORT | HTTP port used by hot reloading in development | 8081 |
31+
| TEMPORAL_HOT_RELOAD_TEST_PORT | HTTP port used by hot reloading in tests | 8082 |
32+
| TEMPORAL_SESSION_SECRET | Secret used to hash the session with HMAC | "ensure secret in production" |
33+
| TEMPORAL_EXTERNAL_SCRIPTS | Additional JavaScript tags to serve in the UI | |
34+
| TEMPORAL_GRPC_MAX_MESSAGE_LENGTH | gRPC max message length (bytes) | 4194304 (4mb) |
35+
| TEMPORAL_CODEC_ENDPOINT | Codec Endpoint, explained below | |
36+
| TEMPORAL_CODEC_PASS_ACCESS_TOKEN | Send OIDC access token to Codec Server | false |
37+
3638

3739
<details>
3840
<summary>
@@ -60,21 +62,21 @@ Setting `TEMPORAL_TLS_REFRESH_INTERVAL` will make the TLS certs reload every N s
6062

6163
</details>
6264

63-
### Configuring Remote Data Encoder (optional)
65+
### Configuring a Codec Endpoint (optional)
6466

65-
If you are using a data converter on your workers to encrypt Temporal Payloads you may wish to deploy a remote data encoder so that your users can see the unencrypted Payloads while using Temporal Web. The documentation for the Temporal SDK you are using for your application should include documentation on how to build a remote data encoder. Please let us know if this is not the case. Once you have a remote data encoder running you can configure Temporal Web to use it to decode Payloads for a user in 2 ways:
67+
If you are using a codec on your workers to encrypt or compress Temporal Payloads you may wish to deploy a codec server so that your users can see the decoded Payloads while using Temporal Web. The samples for the Temporal SDK you are using for your application should include examples of how to build a codec server. Please let us know if this is not the case. Once you have a codec server running you can configure Temporal Web to use it to decode Payloads for a user in 2 ways:
6668

6769
1. Edit the `server/config.yml` file:
6870

6971
```yaml
70-
data_encoder:
71-
endpoint: https://remote_encoder.myorg.com
72+
codec:
73+
endpoint: https://codec.myorg.com
7274
```
73-
2. Set the environment variable TEMPORAL_DATA_ENCODER_ENDPOINT to the URL for your remote data encoder. This is often a more convenient option when running Temporal Web in a docker container.
75+
2. Set the environment variable TEMPORAL_CODEC_ENDPOINT to the URL for your remote codec server. This is often a more convenient option when running Temporal Web in a docker container.
7476
75-
Temporal Web will then configure it's UI to decode Payloads as appropriate via the remote data encoder.
77+
Temporal Web will then configure it's UI to decode Payloads as appropriate via the codec.
7678
77-
Please note that requests to the remote data encoder will be made from the user's browser directly, not via Temporal Web's server. This means that the Temporal Web server will never see the decoded Payloads and does not need to be able to connect to the remote data encoder. This allows using remote data encoders on internal and secure networks while using an externally hosted Temporal Web instance, such that provided by Temporal Cloud.
79+
Please note that requests to the codec server will be made from the user's browser directly, not via Temporal Web's server. This means that the Temporal Web server will never see the decoded Payloads and does not need to be able to connect to the codec server. This allows using codec servers on internal and secure networks while using an externally hosted Temporal Web instance, such that provided by Temporal Cloud.
7880
7981
### Configuring Authentication (optional)
8082

client/features/data-conversion.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import WebSocketAsPromised from 'websocket-as-promised';
22

3-
export const convertEventPayloadsWithRemoteEncoder = async (namespace, events, endpointTemplate) => {
4-
const headers = { 'Content-Type': 'application/json', 'X-Namespace': namespace };
3+
export const convertEventPayloadsWithCodec = async (namespace, events, endpointTemplate, accessToken) => {
4+
let headers = {
5+
'Content-Type': 'application/json',
6+
'X-Namespace': namespace,
7+
};
8+
if (accessToken) {
9+
headers['Authorization'] = `Bearer ${accessToken}`;
10+
}
511
const requests = [];
612
const endpoint = endpointTemplate.replaceAll('{namespace}', namespace);
713

client/routes/workflow/index.vue

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ import {
8080
import { NOTIFICATION_TYPE_ERROR } from '~constants';
8181
import { getErrorMessage } from '~helpers';
8282
import { NavigationBar, NavigationLink } from '~components';
83-
import { convertEventPayloadsWithWebsocket, convertEventPayloadsWithRemoteEncoder } from '~features/data-conversion';
83+
import { convertEventPayloadsWithWebsocket, convertEventPayloadsWithCodec } from '~features/data-conversion';
8484
8585
export default {
8686
data() {
@@ -139,7 +139,7 @@ export default {
139139
)}/${encodeURIComponent(runId)}`;
140140
},
141141
historyUrl() {
142-
const rawPayloads = (this.webSettings?.dataConverter?.port || this.webSettings?.dataEncoder?.endpoint)
142+
const rawPayloads = (this.webSettings?.dataConverter?.port || this.webSettings?.codec?.endpoint)
143143
? '&rawPayloads=true'
144144
: '';
145145
const historyUrl = `${this.baseAPIURL}/history?waitForNewEvent=true${rawPayloads}`;
@@ -205,7 +205,7 @@ export default {
205205
})
206206
.then(events => {
207207
const port = this.webSettings?.dataConverter?.port;
208-
const endpoint = this.webSettings?.dataEncoder?.endpoint;
208+
const endpoint = this.webSettings?.codec?.endpoint;
209209
210210
if (port !== undefined) {
211211
return convertEventPayloadsWithWebsocket(events, port).catch(error => {
@@ -221,7 +221,9 @@ export default {
221221
}
222222
223223
if (endpoint !== undefined) {
224-
return convertEventPayloadsWithRemoteEncoder(this.namespace, events, endpoint).catch(error => {
224+
const accessToken = this.webSettings.codec.accessToken;
225+
226+
return convertEventPayloadsWithCodec(this.namespace, events, endpoint, accessToken).catch(error => {
225227
console.error(error);
226228
227229
this.$emit('onNotification', {

server/config.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ routing:
1717
default_to_namespace: # internal use only
1818
issue_report_link: https://github.com/temporalio/web/issues/new/choose # set this field if you need to direct people to internal support forums
1919

20-
# data_encoder:
21-
# Remote Data Encoder Endpoint
22-
# endpoint: https://remote_encoder.myorg.com
20+
# codec:
21+
# Codec Server Endpoint
22+
# endpoint: https://codec.myorg.com
23+
# pass_access_token: false

server/config/index.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const yaml = require('js-yaml');
44
const logger = require('../logger');
55

66
const configPath = process.env.TEMPORAL_CONFIG_PATH || './server/config.yml';
7-
const dataEncoderEndpoint = process.env.TEMPORAL_DATA_ENCODER_ENDPOINT;
7+
const codecEndpointFromEnv = process.env.TEMPORAL_CODEC_ENDPOINT;
8+
const codecPassAccessTokenFromEnv = process.env.TEMPORAL_CODEC_PASS_ACCESS_TOKEN ? ![false, 'false'].includes(process.env.TEMPORAL_CODEC_PASS_ACCESS_TOKEN) : undefined;
89

910
const readConfigSync = () => {
1011
const cfgContents = readFileSync(configPath, {
@@ -28,16 +29,15 @@ const getAuthConfig = async () => {
2829
return auth;
2930
};
3031

31-
const getDataEncoderConfig = async () => {
32-
let { data_encoder } = await readConfig();
32+
const getCodecConfig = async () => {
33+
let { codec } = await readConfig();
3334

34-
// Data encoder endpoint from the environment takes precedence over
35-
// configuration file value.
36-
const dataEncoderConfig = {
37-
endpoint: dataEncoderEndpoint || data_encoder?.endpoint
35+
const codecConfig = {
36+
endpoint: codecEndpointFromEnv || codec?.endpoint,
37+
passAccessToken: codecPassAccessTokenFromEnv || !!codec?.pass_access_token,
3838
}
3939

40-
return dataEncoderConfig;
40+
return codecConfig;
4141
}
4242

4343
const getRoutingConfig = async () => {
@@ -84,7 +84,7 @@ logger.log(
8484

8585
module.exports = {
8686
getAuthConfig,
87-
getDataEncoderConfig,
87+
getCodecConfig,
8888
getRoutingConfig,
8989
getTlsConfig,
9090
};

server/routes.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const Router = require('koa-router'),
33
moment = require('moment'),
44
losslessJSON = require('lossless-json'),
55
{ isWriteApiPermitted } = require('./utils'),
6-
{ getAuthConfig, getRoutingConfig, getDataEncoderConfig } = require('./config'),
6+
{ getAuthConfig, getRoutingConfig, getCodecConfig } = require('./config'),
77
authRoutes = require('./routes-auth'),
88
{ getTemporalClient: tClient } = require('./temporal-client-provider');
99

@@ -350,22 +350,26 @@ router.post('/api/web-settings/data-converter/:port', async (ctx) => {
350350
ctx.status = 200;
351351
});
352352

353-
router.post('/api/web-settings/remote-data-encoder/:endpoint', async (ctx) => {
354-
ctx.session.dataEncoder = { endpoint: ctx.params.endpoint };
353+
router.post('/api/web-settings/codec/:endpoint', async (ctx) => {
354+
ctx.session.codec = { endpoint: ctx.params.endpoint };
355355
ctx.status = 200;
356356
});
357357

358358
router.get('/api/web-settings', async (ctx) => {
359359
const routing = await getRoutingConfig();
360360
const { enabled } = await getAuthConfig();
361-
const dataEncoder = await getDataEncoderConfig();
361+
const codecConfig = await getCodecConfig();
362362
const permitWriteApi = isWriteApiPermitted();
363363
const dataConverter = ctx.session.dataConverter;
364-
365-
// Encoder endpoint from the session has higher priority than global config.
364+
365+
// Codec endpoint from the session has higher priority than global config.
366366
// This is to allow for testing of new remote encoder endpoints.
367-
if (ctx.session.dataEncoder?.endpoint) {
368-
dataEncoder.endpoint = ctx.session.dataEncoder.endpoint;
367+
let codec = {
368+
endpoint: ctx.session.codec?.endpoint || codecConfig.endpoint
369+
};
370+
371+
if (codecConfig.passAccessToken && !!ctx.state.user) {
372+
codec.accessToken = ctx.state.user.accessToken;
369373
}
370374

371375
const auth = { enabled }; // only include non-sensitive data
@@ -375,7 +379,7 @@ router.get('/api/web-settings', async (ctx) => {
375379
auth,
376380
permitWriteApi,
377381
dataConverter,
378-
dataEncoder,
382+
codec,
379383
};
380384
});
381385

0 commit comments

Comments
 (0)