@telicent-oss/fe-auth-lib 1.0.1 → 1.0.2-TELFE-1477.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +3 -3
  2. package/src/AuthServerOAuth2Client.d.ts +12 -15
  3. package/src/AuthServerOAuth2Client.js +22 -5
  4. package/src/__tests__/callback.failures.test.ts +285 -0
  5. package/src/__tests__/callback.success.test.ts +410 -0
  6. package/src/__tests__/core.failures.test.ts +122 -0
  7. package/src/__tests__/core.success.test.ts +196 -0
  8. package/src/__tests__/env.success.test.ts +17 -0
  9. package/src/__tests__/logout.success.test.ts +151 -0
  10. package/src/__tests__/methods/base64URLEncode.success.test.ts +39 -0
  11. package/src/__tests__/methods/generateCodeChallenge.success.test.ts +43 -0
  12. package/src/__tests__/methods/generateCodeVerifier.success.test.ts +43 -0
  13. package/src/__tests__/methods/generateNonce.success.test.ts +43 -0
  14. package/src/__tests__/methods/generateState.success.test.ts +43 -0
  15. package/src/__tests__/methods/getCsrfToken.failures.test.ts +54 -0
  16. package/src/__tests__/methods/getCsrfToken.success.test.ts +45 -0
  17. package/src/__tests__/methods/getRawIdToken.success.test.ts +39 -0
  18. package/src/__tests__/methods/getUserInfo.failures.test.ts +153 -0
  19. package/src/__tests__/methods/getUserInfo.success.test.ts +84 -0
  20. package/src/__tests__/methods/isAuthenticated.failures.test.ts +62 -0
  21. package/src/__tests__/methods/isAuthenticated.success.test.ts +84 -0
  22. package/src/__tests__/methods/isIdTokenExpired.failures.test.ts +77 -0
  23. package/src/__tests__/methods/isIdTokenExpired.success.test.ts +49 -0
  24. package/src/__tests__/methods/validateIdToken.failures.test.ts +177 -0
  25. package/src/__tests__/methods/validateIdToken.success.test.ts +55 -0
  26. package/src/__tests__/methods/validateIdTokenForRecovery.failures.test.ts +121 -0
  27. package/src/__tests__/methods/validateIdTokenForRecovery.success.test.ts +49 -0
  28. package/src/__tests__/popup.success.test.ts +277 -0
  29. package/src/__tests__/request-helpers.failures.test.ts +143 -0
  30. package/src/__tests__/request-helpers.success.test.ts +137 -0
  31. package/src/__tests__/schema-loading.failures.test.ts +44 -0
  32. package/src/__tests__/schema-loading.success.test.ts +106 -0
  33. package/src/__tests__/state.success.test.ts +217 -0
  34. package/src/__tests__/test-utils.node.success.test.ts +16 -0
  35. package/src/__tests__/test-utils.success.test.ts +188 -0
  36. package/src/__tests__/test-utils.ts +203 -0
@@ -0,0 +1,196 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../AuthServerOAuth2Client";
4
+ import {
5
+ installTestEnv,
6
+ mockPkceValues,
7
+ resetTestEnv,
8
+ setWindowLocation,
9
+ } from "./test-utils";
10
+
11
+ const createConfig = (
12
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
13
+ ) => ({
14
+ clientId: "client-1",
15
+ authServerUrl: "http://auth.telicent.localhost",
16
+ redirectUri: "http://app.telicent.localhost/callback",
17
+ popupRedirectUri: "http://app.telicent.localhost/popup",
18
+ scope: "openid profile",
19
+ onLogout: jest.fn(),
20
+ ...overrides,
21
+ });
22
+
23
+ describe("happy path - constructor, domain detection, pkce, and login", () => {
24
+ beforeEach(() => {
25
+ installTestEnv();
26
+ setWindowLocation("http://app.telicent.localhost/home");
27
+ });
28
+
29
+ afterEach(() => {
30
+ resetTestEnv();
31
+ });
32
+
33
+ it("constructs client and detects same-domain", () => {
34
+ const client = new AuthServerOAuth2Client(createConfig());
35
+
36
+ expect({
37
+ clientId: client.config.clientId,
38
+ isCrossDomain: client.isCrossDomain,
39
+ }).toMatchInlineSnapshot(`
40
+ {
41
+ "clientId": "client-1",
42
+ "isCrossDomain": false,
43
+ }
44
+ `);
45
+ });
46
+
47
+ it("detects domains across common cases", () => {
48
+ const cases = [
49
+ {
50
+ current: "http://localhost",
51
+ authServerUrl: "http://localhost",
52
+ },
53
+ {
54
+ current: "http://app.telicent.localhost",
55
+ authServerUrl: "http://auth.telicent.localhost",
56
+ },
57
+ {
58
+ current: "http://localhost:3000",
59
+ authServerUrl: "https://dev.telicent.io",
60
+ },
61
+ ];
62
+
63
+ const results = cases.map((item) => {
64
+ setWindowLocation(item.current);
65
+ const client = new AuthServerOAuth2Client(
66
+ createConfig({ authServerUrl: item.authServerUrl })
67
+ );
68
+ return {
69
+ current: item.current,
70
+ auth: item.authServerUrl,
71
+ isCrossDomain: client.isCrossDomain,
72
+ };
73
+ });
74
+
75
+ expect(results).toMatchInlineSnapshot(`
76
+ [
77
+ {
78
+ "auth": "http://localhost",
79
+ "current": "http://localhost",
80
+ "isCrossDomain": false,
81
+ },
82
+ {
83
+ "auth": "http://auth.telicent.localhost",
84
+ "current": "http://app.telicent.localhost",
85
+ "isCrossDomain": false,
86
+ },
87
+ {
88
+ "auth": "https://dev.telicent.io",
89
+ "current": "http://localhost:3000",
90
+ "isCrossDomain": true,
91
+ },
92
+ ]
93
+ `);
94
+ });
95
+
96
+ it("generates readable pkce values, state, and nonce", async () => {
97
+ const client = new AuthServerOAuth2Client(createConfig());
98
+ const values = mockPkceValues(client);
99
+ const codeVerifier = client.generateCodeVerifier();
100
+ const codeChallenge = await client.generateCodeChallenge(codeVerifier);
101
+ const state = client.generateState();
102
+ const nonce = client.generateNonce();
103
+
104
+ expect({
105
+ codeVerifier,
106
+ codeChallenge,
107
+ state,
108
+ nonce,
109
+ }).toMatchInlineSnapshot(`
110
+ {
111
+ "codeChallenge": "ABC_codeChallenge_ABC",
112
+ "codeVerifier": "ABC_codeVerifier_ABC",
113
+ "nonce": "ABC_nonce_ABC",
114
+ "state": "ABC_state_ABC",
115
+ }
116
+ `);
117
+
118
+ expect(values).toMatchInlineSnapshot(`
119
+ {
120
+ "codeChallenge": "ABC_codeChallenge_ABC",
121
+ "codeVerifier": "ABC_codeVerifier_ABC",
122
+ "nonce": "ABC_nonce_ABC",
123
+ "state": "ABC_state_ABC",
124
+ }
125
+ `);
126
+ });
127
+
128
+ it("builds login redirect and stores pkce values", async () => {
129
+ const client = new AuthServerOAuth2Client(createConfig());
130
+ mockPkceValues(client);
131
+ await client.login();
132
+
133
+ const url = new URL(window.location.href);
134
+ const params = Object.fromEntries(url.searchParams.entries());
135
+
136
+ expect({
137
+ href: window.location.href,
138
+ params,
139
+ storage: {
140
+ state: sessionStorage.getItem("oauth_state"),
141
+ nonce: sessionStorage.getItem("oauth_nonce"),
142
+ codeVerifier: sessionStorage.getItem("oauth_code_verifier"),
143
+ redirectUri: sessionStorage.getItem("oauth_redirect_uri"),
144
+ },
145
+ }).toMatchInlineSnapshot(`
146
+ {
147
+ "href": "http://auth.telicent.localhost/oauth2/authorize?response_type=code&client_id=client-1&redirect_uri=http%3A%2F%2Fapp.telicent.localhost%2Fcallback&scope=openid+profile&state=ABC_state_ABC.aHR0cDovL2FwcC50ZWxpY2VudC5sb2NhbGhvc3QvaG9tZQ&nonce=ABC_nonce_ABC&code_challenge=ABC_codeChallenge_ABC&code_challenge_method=S256",
148
+ "params": {
149
+ "client_id": "client-1",
150
+ "code_challenge": "ABC_codeChallenge_ABC",
151
+ "code_challenge_method": "S256",
152
+ "nonce": "ABC_nonce_ABC",
153
+ "redirect_uri": "http://app.telicent.localhost/callback",
154
+ "response_type": "code",
155
+ "scope": "openid profile",
156
+ "state": "ABC_state_ABC.aHR0cDovL2FwcC50ZWxpY2VudC5sb2NhbGhvc3QvaG9tZQ",
157
+ },
158
+ "storage": {
159
+ "codeVerifier": "ABC_codeVerifier_ABC",
160
+ "nonce": "ABC_nonce_ABC",
161
+ "redirectUri": "http://app.telicent.localhost/callback",
162
+ "state": "ABC_state_ABC",
163
+ },
164
+ }
165
+ `);
166
+ });
167
+
168
+ it("opens popup and starts flow", async () => {
169
+ const client = new AuthServerOAuth2Client(createConfig());
170
+ mockPkceValues(client);
171
+ const popup = { close: jest.fn(), closed: false } as unknown as Window;
172
+ const openSpy = jest.spyOn(window, "open").mockReturnValue(popup);
173
+ const startSpy = jest.spyOn(client, "startPopupFlow");
174
+
175
+ await client.loginWithPopup();
176
+
177
+ expect({
178
+ openArgs: openSpy.mock.calls[0],
179
+ startCalls: startSpy.mock.calls.length,
180
+ state: sessionStorage.getItem("oauth_state"),
181
+ }).toMatchInlineSnapshot(`
182
+ {
183
+ "openArgs": [
184
+ "http://auth.telicent.localhost/oauth2/authorize?response_type=code&client_id=client-1&redirect_uri=http%3A%2F%2Fapp.telicent.localhost%2Fpopup&scope=openid+profile&state=ABC_state_ABC&nonce=ABC_nonce_ABC&code_challenge=ABC_codeChallenge_ABC&code_challenge_method=S256",
185
+ "_blank",
186
+ "width=600,height=700,scrollbars=yes,resizable=yes",
187
+ ],
188
+ "startCalls": 1,
189
+ "state": "ABC_state_ABC",
190
+ }
191
+ `);
192
+
193
+ openSpy.mockRestore();
194
+ startSpy.mockRestore();
195
+ });
196
+ });
@@ -0,0 +1,17 @@
1
+ describe("happy path - jsdom environment", () => {
2
+ it("exposes browser globals", () => {
3
+ const result = {
4
+ hasWindow: typeof window !== "undefined",
5
+ hasDocument: typeof document !== "undefined",
6
+ hasSessionStorage: typeof sessionStorage !== "undefined",
7
+ };
8
+
9
+ expect(result).toMatchInlineSnapshot(`
10
+ {
11
+ "hasDocument": true,
12
+ "hasSessionStorage": true,
13
+ "hasWindow": true,
14
+ }
15
+ `);
16
+ });
17
+ });
@@ -0,0 +1,151 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../AuthServerOAuth2Client";
4
+ import { installTestEnv, resetTestEnv } from "./test-utils";
5
+
6
+ const createConfig = (
7
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
8
+ ): AuthServerOAuth2ClientConfig => ({
9
+ clientId: "client-1",
10
+ authServerUrl: "http://auth.telicent.localhost",
11
+ redirectUri: "http://app.telicent.localhost/callback",
12
+ popupRedirectUri: "http://app.telicent.localhost/popup",
13
+ scope: "openid profile",
14
+ onLogout: jest.fn(),
15
+ ...overrides,
16
+ });
17
+
18
+ const createFetchResponse = (options: {
19
+ ok?: boolean;
20
+ jsonData?: unknown;
21
+ }): Response =>
22
+ ({
23
+ ok: options.ok ?? true,
24
+ json: jest.fn().mockResolvedValue(options.jsonData ?? {}),
25
+ } as unknown as Response);
26
+
27
+ describe("happy path - logout flows", () => {
28
+ beforeEach(() => {
29
+ installTestEnv();
30
+ });
31
+
32
+ afterEach(() => {
33
+ resetTestEnv();
34
+ });
35
+
36
+ it("handles external logout redirect", async () => {
37
+ const client = new AuthServerOAuth2Client(createConfig());
38
+ const fetchMock = jest.fn().mockResolvedValue(
39
+ createFetchResponse({
40
+ jsonData: {
41
+ external_logout: true,
42
+ logout_url: "https://idp.example.com/logout",
43
+ },
44
+ })
45
+ );
46
+ globalThis.fetch = fetchMock;
47
+
48
+ await client.logout();
49
+
50
+ expect({
51
+ location: window.location.href,
52
+ onLogoutCalls: (client.config.onLogout as jest.Mock).mock.calls.length,
53
+ }).toMatchInlineSnapshot(`
54
+ {
55
+ "location": "http://localhost/",
56
+ "onLogoutCalls": 0,
57
+ }
58
+ `);
59
+ });
60
+
61
+ it("includes Authorization header for cross-domain logout", async () => {
62
+ const client = new AuthServerOAuth2Client(
63
+ createConfig({ authServerUrl: "https://auth.telicent.io" })
64
+ );
65
+ sessionStorage.setItem("auth_session_id", "SESSION_123");
66
+ const fetchMock = jest.fn().mockResolvedValue(
67
+ createFetchResponse({ jsonData: {} })
68
+ );
69
+ globalThis.fetch = fetchMock;
70
+
71
+ await client.logout();
72
+
73
+ expect({
74
+ headers: fetchMock.mock.calls[0][1]?.headers,
75
+ }).toMatchInlineSnapshot(`
76
+ {
77
+ "headers": {
78
+ "Accept": "application/json",
79
+ "Authorization": "Bearer SESSION_123",
80
+ },
81
+ }
82
+ `);
83
+ });
84
+
85
+ it("continues logout when response is not json", async () => {
86
+ const onLogout = jest.fn();
87
+ const client = new AuthServerOAuth2Client(createConfig({ onLogout }));
88
+ const fetchMock = jest.fn().mockResolvedValue(
89
+ ({
90
+ ok: true,
91
+ json: jest.fn().mockRejectedValue(new Error("bad json")),
92
+ } as unknown as Response)
93
+ );
94
+ globalThis.fetch = fetchMock;
95
+
96
+ await client.logout();
97
+
98
+ expect({
99
+ onLogoutCalls: onLogout.mock.calls.length,
100
+ warnings: (console.warn as jest.Mock).mock.calls.map((call) => call[0]),
101
+ }).toMatchInlineSnapshot(`
102
+ {
103
+ "onLogoutCalls": 1,
104
+ "warnings": [
105
+ "Logout response is not JSON, continuing with standard logout",
106
+ ],
107
+ }
108
+ `);
109
+ });
110
+
111
+ it("continues logout when fetch throws", async () => {
112
+ const onLogout = jest.fn();
113
+ const client = new AuthServerOAuth2Client(createConfig({ onLogout }));
114
+ globalThis.fetch = jest.fn().mockRejectedValue(new Error("network"));
115
+
116
+ await client.logout();
117
+
118
+ expect({
119
+ onLogoutCalls: onLogout.mock.calls.length,
120
+ errors: (console.error as jest.Mock).mock.calls.map((call) => call[0]),
121
+ }).toMatchInlineSnapshot(`
122
+ {
123
+ "errors": [
124
+ "Logout error (ignoring):",
125
+ ],
126
+ "onLogoutCalls": 1,
127
+ }
128
+ `);
129
+ });
130
+
131
+ it("calls onLogout on standard logout", async () => {
132
+ const onLogout = jest.fn();
133
+ const client = new AuthServerOAuth2Client(createConfig({ onLogout }));
134
+ const fetchMock = jest.fn().mockResolvedValue(
135
+ createFetchResponse({
136
+ jsonData: {},
137
+ })
138
+ );
139
+ globalThis.fetch = fetchMock;
140
+
141
+ await client.logout();
142
+
143
+ expect({
144
+ onLogoutCalls: onLogout.mock.calls.length,
145
+ }).toMatchInlineSnapshot(`
146
+ {
147
+ "onLogoutCalls": 1,
148
+ }
149
+ `);
150
+ });
151
+ });
@@ -0,0 +1,39 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../../AuthServerOAuth2Client";
4
+ import { installTestEnv, resetTestEnv } from "../test-utils";
5
+
6
+ const createConfig = (
7
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
8
+ ): AuthServerOAuth2ClientConfig => ({
9
+ clientId: "client-1",
10
+ authServerUrl: "http://auth.telicent.localhost",
11
+ redirectUri: "http://app.telicent.localhost/callback",
12
+ popupRedirectUri: "http://app.telicent.localhost/popup",
13
+ scope: "openid profile",
14
+ onLogout: jest.fn(),
15
+ ...overrides,
16
+ });
17
+
18
+ describe("happy path - base64URLEncode", () => {
19
+ beforeEach(() => {
20
+ installTestEnv();
21
+ });
22
+
23
+ afterEach(() => {
24
+ resetTestEnv();
25
+ });
26
+
27
+ it("encodes bytes to base64url", () => {
28
+ const client = new AuthServerOAuth2Client(createConfig());
29
+ const bytes = new Uint8Array([65, 66, 67]);
30
+
31
+ const result = client.base64URLEncode(bytes);
32
+
33
+ expect({ result }).toMatchInlineSnapshot(`
34
+ {
35
+ "result": "QUJD",
36
+ }
37
+ `);
38
+ });
39
+ });
@@ -0,0 +1,43 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../../AuthServerOAuth2Client";
4
+ import {
5
+ installCryptoMock,
6
+ installTestEnv,
7
+ resetTestEnv,
8
+ } from "../test-utils";
9
+
10
+ const createConfig = (
11
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
12
+ ): AuthServerOAuth2ClientConfig => ({
13
+ clientId: "client-1",
14
+ authServerUrl: "http://auth.telicent.localhost",
15
+ redirectUri: "http://app.telicent.localhost/callback",
16
+ popupRedirectUri: "http://app.telicent.localhost/popup",
17
+ scope: "openid profile",
18
+ onLogout: jest.fn(),
19
+ ...overrides,
20
+ });
21
+
22
+ describe("happy path - generateCodeChallenge", () => {
23
+ beforeEach(() => {
24
+ installTestEnv();
25
+ installCryptoMock({ digestBytes: [65, 66, 67] });
26
+ });
27
+
28
+ afterEach(() => {
29
+ resetTestEnv();
30
+ });
31
+
32
+ it("returns challenge", async () => {
33
+ const client = new AuthServerOAuth2Client(createConfig());
34
+
35
+ const result = await client.generateCodeChallenge("VERIFIER");
36
+
37
+ expect({ result }).toMatchInlineSnapshot(`
38
+ {
39
+ "result": "QUJD",
40
+ }
41
+ `);
42
+ });
43
+ });
@@ -0,0 +1,43 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../../AuthServerOAuth2Client";
4
+ import {
5
+ installCryptoMock,
6
+ installTestEnv,
7
+ resetTestEnv,
8
+ } from "../test-utils";
9
+
10
+ const createConfig = (
11
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
12
+ ): AuthServerOAuth2ClientConfig => ({
13
+ clientId: "client-1",
14
+ authServerUrl: "http://auth.telicent.localhost",
15
+ redirectUri: "http://app.telicent.localhost/callback",
16
+ popupRedirectUri: "http://app.telicent.localhost/popup",
17
+ scope: "openid profile",
18
+ onLogout: jest.fn(),
19
+ ...overrides,
20
+ });
21
+
22
+ describe("happy path - generateCodeVerifier", () => {
23
+ beforeEach(() => {
24
+ installTestEnv();
25
+ installCryptoMock({ fillByte: 65 });
26
+ });
27
+
28
+ afterEach(() => {
29
+ resetTestEnv();
30
+ });
31
+
32
+ it("returns verifier", () => {
33
+ const client = new AuthServerOAuth2Client(createConfig());
34
+
35
+ const result = client.generateCodeVerifier();
36
+
37
+ expect({ result }).toMatchInlineSnapshot(`
38
+ {
39
+ "result": "QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE",
40
+ }
41
+ `);
42
+ });
43
+ });
@@ -0,0 +1,43 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../../AuthServerOAuth2Client";
4
+ import {
5
+ installCryptoMock,
6
+ installTestEnv,
7
+ resetTestEnv,
8
+ } from "../test-utils";
9
+
10
+ const createConfig = (
11
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
12
+ ): AuthServerOAuth2ClientConfig => ({
13
+ clientId: "client-1",
14
+ authServerUrl: "http://auth.telicent.localhost",
15
+ redirectUri: "http://app.telicent.localhost/callback",
16
+ popupRedirectUri: "http://app.telicent.localhost/popup",
17
+ scope: "openid profile",
18
+ onLogout: jest.fn(),
19
+ ...overrides,
20
+ });
21
+
22
+ describe("happy path - generateNonce", () => {
23
+ beforeEach(() => {
24
+ installTestEnv();
25
+ installCryptoMock({ fillByte: 66 });
26
+ });
27
+
28
+ afterEach(() => {
29
+ resetTestEnv();
30
+ });
31
+
32
+ it("returns nonce", () => {
33
+ const client = new AuthServerOAuth2Client(createConfig());
34
+
35
+ const result = client.generateNonce();
36
+
37
+ expect({ result }).toMatchInlineSnapshot(`
38
+ {
39
+ "result": "QkJCQkJCQkJCQkJCQkJCQg",
40
+ }
41
+ `);
42
+ });
43
+ });
@@ -0,0 +1,43 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../../AuthServerOAuth2Client";
4
+ import {
5
+ installCryptoMock,
6
+ installTestEnv,
7
+ resetTestEnv,
8
+ } from "../test-utils";
9
+
10
+ const createConfig = (
11
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
12
+ ): AuthServerOAuth2ClientConfig => ({
13
+ clientId: "client-1",
14
+ authServerUrl: "http://auth.telicent.localhost",
15
+ redirectUri: "http://app.telicent.localhost/callback",
16
+ popupRedirectUri: "http://app.telicent.localhost/popup",
17
+ scope: "openid profile",
18
+ onLogout: jest.fn(),
19
+ ...overrides,
20
+ });
21
+
22
+ describe("happy path - generateState", () => {
23
+ beforeEach(() => {
24
+ installTestEnv();
25
+ installCryptoMock({ fillByte: 67 });
26
+ });
27
+
28
+ afterEach(() => {
29
+ resetTestEnv();
30
+ });
31
+
32
+ it("returns state", () => {
33
+ const client = new AuthServerOAuth2Client(createConfig());
34
+
35
+ const result = client.generateState();
36
+
37
+ expect({ result }).toMatchInlineSnapshot(`
38
+ {
39
+ "result": "Q0NDQ0NDQ0NDQ0NDQ0NDQw",
40
+ }
41
+ `);
42
+ });
43
+ });
@@ -0,0 +1,54 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../../AuthServerOAuth2Client";
4
+ import { installTestEnv, resetTestEnv, setWindowLocation } from "../test-utils";
5
+
6
+ const createConfig = (
7
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
8
+ ): AuthServerOAuth2ClientConfig => ({
9
+ clientId: "client-1",
10
+ authServerUrl: "http://auth.telicent.localhost",
11
+ redirectUri: "http://app.telicent.localhost/callback",
12
+ popupRedirectUri: "http://app.telicent.localhost/popup",
13
+ scope: "openid profile",
14
+ onLogout: jest.fn(),
15
+ ...overrides,
16
+ });
17
+
18
+ describe("failure path - getCsrfToken errors", () => {
19
+ beforeEach(() => {
20
+ installTestEnv();
21
+ });
22
+
23
+ afterEach(() => {
24
+ resetTestEnv();
25
+ });
26
+
27
+ it("returns null for cross-domain clients", () => {
28
+ setWindowLocation("http://app.telicent.localhost/home");
29
+ const client = new AuthServerOAuth2Client(
30
+ createConfig({ authServerUrl: "https://auth.telicent.io" })
31
+ );
32
+
33
+ const result = client.getCsrfToken();
34
+
35
+ expect({ result }).toMatchInlineSnapshot(`
36
+ {
37
+ "result": null,
38
+ }
39
+ `);
40
+ });
41
+
42
+ it("returns null when cookie is missing", () => {
43
+ setWindowLocation("http://app.telicent.localhost/home");
44
+ const client = new AuthServerOAuth2Client(createConfig());
45
+
46
+ const result = client.getCsrfToken();
47
+
48
+ expect({ result }).toMatchInlineSnapshot(`
49
+ {
50
+ "result": null,
51
+ }
52
+ `);
53
+ });
54
+ });
@@ -0,0 +1,45 @@
1
+ import AuthServerOAuth2Client, {
2
+ AuthServerOAuth2ClientConfig,
3
+ } from "../../AuthServerOAuth2Client";
4
+ import {
5
+ installTestEnv,
6
+ resetTestEnv,
7
+ setCookies,
8
+ setWindowLocation,
9
+ } from "../test-utils";
10
+
11
+ const createConfig = (
12
+ overrides: Partial<AuthServerOAuth2ClientConfig> = {}
13
+ ): AuthServerOAuth2ClientConfig => ({
14
+ clientId: "client-1",
15
+ authServerUrl: "http://auth.telicent.localhost",
16
+ redirectUri: "http://app.telicent.localhost/callback",
17
+ popupRedirectUri: "http://app.telicent.localhost/popup",
18
+ scope: "openid profile",
19
+ onLogout: jest.fn(),
20
+ ...overrides,
21
+ });
22
+
23
+ describe("happy path - getCsrfToken returns cookie token", () => {
24
+ beforeEach(() => {
25
+ installTestEnv();
26
+ setWindowLocation("http://app.telicent.localhost/home");
27
+ });
28
+
29
+ afterEach(() => {
30
+ resetTestEnv();
31
+ });
32
+
33
+ it("returns decoded csrf token for same-domain", () => {
34
+ const client = new AuthServerOAuth2Client(createConfig());
35
+ setCookies("XSRF-TOKEN=csrf-123");
36
+
37
+ const result = client.getCsrfToken();
38
+
39
+ expect({ result }).toMatchInlineSnapshot(`
40
+ {
41
+ "result": "csrf-123",
42
+ }
43
+ `);
44
+ });
45
+ });