Skip to content

Commit f6b3a93

Browse files
authored
feat: Added support for Authenticated Datafiles (#498)
Summary: Added support for Authenticated Datafiles
1 parent cc6a6b6 commit f6b3a93

File tree

5 files changed

+114
-2
lines changed

5 files changed

+114
-2
lines changed

packages/datafile-manager/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77
## [Unreleased]
88
Changes that have landed but are not yet released.
99

10+
### Changed
11+
- Added support for authenticated datafiles. `NodeDatafileManager` now accepts `datafileAccessToken` to be able to fetch authenticated datafiles.
12+
1013
## [0.5.0] - April 17, 2020
1114

1215
### Breaking Changes

packages/datafile-manager/__test__/nodeDatafileManager.spec.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,80 @@ describe('nodeDatafileManager', () => {
104104

105105
await manager.stop();
106106
});
107+
108+
it('uses authenticated default datafile url when auth token is provided', async () => {
109+
makeGetRequestSpy.mockReturnValue({
110+
abort: jest.fn(),
111+
responsePromise: Promise.resolve({
112+
statusCode: 200,
113+
body: '{"foo":"bar"}',
114+
headers: {},
115+
}),
116+
});
117+
const manager = new NodeDatafileManager({
118+
sdkKey: '1234',
119+
datafileAccessToken: 'abcdefgh',
120+
});
121+
manager.start();
122+
expect(makeGetRequestSpy).toBeCalledTimes(1);
123+
expect(makeGetRequestSpy).toBeCalledWith('https://www.optimizely-cdn.com/datafiles/auth/1234.json', expect.anything());
124+
await manager.stop();
125+
});
126+
127+
it('uses public default datafile url when auth token is not provided', async () => {
128+
makeGetRequestSpy.mockReturnValue({
129+
abort: jest.fn(),
130+
responsePromise: Promise.resolve({
131+
statusCode: 200,
132+
body: '{"foo":"bar"}',
133+
headers: {},
134+
}),
135+
});
136+
const manager = new NodeDatafileManager({
137+
sdkKey: '1234',
138+
});
139+
manager.start();
140+
expect(makeGetRequestSpy).toBeCalledTimes(1);
141+
expect(makeGetRequestSpy).toBeCalledWith('https://cdn.optimizely.com/datafiles/1234.json', expect.anything());
142+
await manager.stop();
143+
});
144+
145+
it('adds authorization header with bearer token when auth token is provided', async () => {
146+
makeGetRequestSpy.mockReturnValue({
147+
abort: jest.fn(),
148+
responsePromise: Promise.resolve({
149+
statusCode: 200,
150+
body: '{"foo":"bar"}',
151+
headers: {},
152+
}),
153+
});
154+
const manager = new NodeDatafileManager({
155+
sdkKey: '1234',
156+
datafileAccessToken: 'abcdefgh',
157+
});
158+
manager.start();
159+
expect(makeGetRequestSpy).toBeCalledTimes(1);
160+
expect(makeGetRequestSpy).toBeCalledWith(expect.anything(), { 'Authorization': 'Bearer abcdefgh'});
161+
await manager.stop();
162+
});
163+
164+
it('prefers user provided url template over defaults', async () => {
165+
makeGetRequestSpy.mockReturnValue({
166+
abort: jest.fn(),
167+
responsePromise: Promise.resolve({
168+
statusCode: 200,
169+
body: '{"foo":"bar"}',
170+
headers: {},
171+
}),
172+
});
173+
const manager = new NodeDatafileManager({
174+
sdkKey: '1234',
175+
datafileAccessToken: 'abcdefgh',
176+
urlTemplate: 'https://myawesomeurl/'
177+
});
178+
manager.start();
179+
expect(makeGetRequestSpy).toBeCalledTimes(1);
180+
expect(makeGetRequestSpy).toBeCalledWith('https://myawesomeurl/', expect.anything());
181+
await manager.stop();
182+
});
107183
});

packages/datafile-manager/src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export const MIN_UPDATE_INTERVAL = 1000;
2020

2121
export const DEFAULT_URL_TEMPLATE = `https://cdn.optimizely.com/datafiles/%s.json`;
2222

23+
export const DEFAULT_AUTHENTICATED_URL_TEMPLATE = `https://www.optimizely-cdn.com/datafiles/auth/%s.json`;
24+
2325
export const BACKOFF_BASE_WAIT_SECONDS_BY_ERROR_COUNT = [0, 8, 16, 32, 64, 128, 256, 512];
2426

2527
export const REQUEST_TIMEOUT_MS = 60 * 1000; // 1 minute

packages/datafile-manager/src/datafileManager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,7 @@ export interface DatafileManagerConfig {
4444
urlTemplate?: string;
4545
cache?: PersistentKeyValueCache;
4646
}
47+
48+
export interface NodeDatafileManagerConfig extends DatafileManagerConfig {
49+
datafileAccessToken?: string;
50+
}

packages/datafile-manager/src/nodeDatafileManager.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,41 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { getLogger } from '@optimizely/js-sdk-logging';
1718
import { makeGetRequest } from './nodeRequest';
1819
import HttpPollingDatafileManager from './httpPollingDatafileManager';
1920
import { Headers, AbortableRequest } from './http';
20-
import { DatafileManagerConfig } from './datafileManager';
21+
import {
22+
NodeDatafileManagerConfig,
23+
DatafileManagerConfig,
24+
} from './datafileManager';
25+
import {
26+
DEFAULT_URL_TEMPLATE,
27+
DEFAULT_AUTHENTICATED_URL_TEMPLATE,
28+
} from './config';
29+
30+
const logger = getLogger('NodeDatafileManager');
2131

2232
export default class NodeDatafileManager extends HttpPollingDatafileManager {
33+
34+
private accessToken?: string;
35+
36+
constructor(config: NodeDatafileManagerConfig) {
37+
const defaultUrlTemplate = config.datafileAccessToken ? DEFAULT_AUTHENTICATED_URL_TEMPLATE : DEFAULT_URL_TEMPLATE;
38+
super({
39+
... config,
40+
urlTemplate: config.urlTemplate || defaultUrlTemplate,
41+
});
42+
this.accessToken = config.datafileAccessToken;
43+
}
44+
2345
protected makeGetRequest(reqUrl: string, headers: Headers): AbortableRequest {
24-
return makeGetRequest(reqUrl, headers);
46+
let requestHeaders = Object.assign({}, headers);
47+
if (this.accessToken) {
48+
logger.debug('Adding Authorization header with Bearer Token');
49+
requestHeaders['Authorization'] = `Bearer ${this.accessToken}`;
50+
}
51+
return makeGetRequest(reqUrl, requestHeaders);
2552
}
2653

2754
protected getConfigDefaults(): Partial<DatafileManagerConfig> {

0 commit comments

Comments
 (0)