@telicent-oss/fe-auth-lib 1.0.0 → 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.
- package/package.json +3 -3
- package/src/AuthServerOAuth2Client.d.ts +12 -15
- package/src/AuthServerOAuth2Client.js +21 -10
- package/src/__tests__/callback.failures.test.ts +285 -0
- package/src/__tests__/callback.success.test.ts +410 -0
- package/src/__tests__/core.failures.test.ts +122 -0
- package/src/__tests__/core.success.test.ts +196 -0
- package/src/__tests__/env.success.test.ts +17 -0
- package/src/__tests__/logout.success.test.ts +151 -0
- package/src/__tests__/methods/base64URLEncode.success.test.ts +39 -0
- package/src/__tests__/methods/generateCodeChallenge.success.test.ts +43 -0
- package/src/__tests__/methods/generateCodeVerifier.success.test.ts +43 -0
- package/src/__tests__/methods/generateNonce.success.test.ts +43 -0
- package/src/__tests__/methods/generateState.success.test.ts +43 -0
- package/src/__tests__/methods/getCsrfToken.failures.test.ts +54 -0
- package/src/__tests__/methods/getCsrfToken.success.test.ts +45 -0
- package/src/__tests__/methods/getRawIdToken.success.test.ts +39 -0
- package/src/__tests__/methods/getUserInfo.failures.test.ts +153 -0
- package/src/__tests__/methods/getUserInfo.success.test.ts +84 -0
- package/src/__tests__/methods/isAuthenticated.failures.test.ts +62 -0
- package/src/__tests__/methods/isAuthenticated.success.test.ts +84 -0
- package/src/__tests__/methods/isIdTokenExpired.failures.test.ts +77 -0
- package/src/__tests__/methods/isIdTokenExpired.success.test.ts +49 -0
- package/src/__tests__/methods/validateIdToken.failures.test.ts +177 -0
- package/src/__tests__/methods/validateIdToken.success.test.ts +55 -0
- package/src/__tests__/methods/validateIdTokenForRecovery.failures.test.ts +121 -0
- package/src/__tests__/methods/validateIdTokenForRecovery.success.test.ts +49 -0
- package/src/__tests__/popup.success.test.ts +277 -0
- package/src/__tests__/request-helpers.failures.test.ts +143 -0
- package/src/__tests__/request-helpers.success.test.ts +137 -0
- package/src/__tests__/schema-loading.failures.test.ts +44 -0
- package/src/__tests__/schema-loading.success.test.ts +106 -0
- package/src/__tests__/state.success.test.ts +217 -0
- package/src/__tests__/test-utils.node.success.test.ts +16 -0
- package/src/__tests__/test-utils.success.test.ts +188 -0
- package/src/__tests__/test-utils.ts +203 -0
|
@@ -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 - getRawIdToken returns stored token", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
installTestEnv();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
resetTestEnv();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("returns auth_id_token from storage", () => {
|
|
28
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
29
|
+
sessionStorage.setItem("auth_id_token", "RAW_TOKEN");
|
|
30
|
+
|
|
31
|
+
const result = client.getRawIdToken();
|
|
32
|
+
|
|
33
|
+
expect({ result }).toMatchInlineSnapshot(`
|
|
34
|
+
{
|
|
35
|
+
"result": "RAW_TOKEN",
|
|
36
|
+
}
|
|
37
|
+
`);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import AuthServerOAuth2Client, {
|
|
2
|
+
AuthServerOAuth2ClientConfig,
|
|
3
|
+
} from "../../AuthServerOAuth2Client";
|
|
4
|
+
import { buildJwt, 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("failure path - getUserInfo errors", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
installTestEnv();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
resetTestEnv();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("returns null when token is missing", () => {
|
|
28
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
29
|
+
|
|
30
|
+
const info = client.getUserInfo();
|
|
31
|
+
|
|
32
|
+
expect({ info }).toMatchInlineSnapshot(`
|
|
33
|
+
{
|
|
34
|
+
"info": null,
|
|
35
|
+
}
|
|
36
|
+
`);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("returns null for invalid token", () => {
|
|
40
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
41
|
+
sessionStorage.setItem("auth_id_token", "not-a-jwt");
|
|
42
|
+
|
|
43
|
+
const info = client.getUserInfo();
|
|
44
|
+
|
|
45
|
+
expect({ info }).toMatchInlineSnapshot(`
|
|
46
|
+
{
|
|
47
|
+
"info": null,
|
|
48
|
+
}
|
|
49
|
+
`);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("returns null for expired token", () => {
|
|
53
|
+
const now = 1_700_000_000_000;
|
|
54
|
+
jest.spyOn(Date, "now").mockReturnValue(now);
|
|
55
|
+
|
|
56
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
57
|
+
const token = buildJwt({
|
|
58
|
+
sub: "user-1",
|
|
59
|
+
aud: "client-1",
|
|
60
|
+
exp: Math.floor(now / 1000) - 10,
|
|
61
|
+
iat: Math.floor(now / 1000) - 100,
|
|
62
|
+
email: "user@example.com",
|
|
63
|
+
preferred_name: "User One",
|
|
64
|
+
iss: "http://auth.telicent.localhost",
|
|
65
|
+
jti: "id-1",
|
|
66
|
+
});
|
|
67
|
+
sessionStorage.setItem("auth_id_token", token);
|
|
68
|
+
|
|
69
|
+
const info = client.getUserInfo();
|
|
70
|
+
|
|
71
|
+
expect({ info }).toMatchInlineSnapshot(`
|
|
72
|
+
{
|
|
73
|
+
"info": null,
|
|
74
|
+
}
|
|
75
|
+
`);
|
|
76
|
+
|
|
77
|
+
(Date.now as jest.Mock).mockRestore();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("returns unvalidated info when schema validation fails", () => {
|
|
81
|
+
const now = 1_700_000_000_000;
|
|
82
|
+
jest.spyOn(Date, "now").mockReturnValue(now);
|
|
83
|
+
|
|
84
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
85
|
+
const token = buildJwt({
|
|
86
|
+
sub: "user-1",
|
|
87
|
+
aud: "client-1",
|
|
88
|
+
exp: Math.floor(now / 1000) + 300,
|
|
89
|
+
iat: Math.floor(now / 1000),
|
|
90
|
+
iss: "http://auth.telicent.localhost",
|
|
91
|
+
jti: "id-1",
|
|
92
|
+
});
|
|
93
|
+
sessionStorage.setItem("auth_id_token", token);
|
|
94
|
+
|
|
95
|
+
const info = client.getUserInfo();
|
|
96
|
+
|
|
97
|
+
expect({
|
|
98
|
+
info,
|
|
99
|
+
warnings: (console.warn as jest.Mock).mock.calls.map((call) => call[0]),
|
|
100
|
+
}).toMatchInlineSnapshot(`
|
|
101
|
+
{
|
|
102
|
+
"info": {
|
|
103
|
+
"aud": "client-1",
|
|
104
|
+
"auth_time": undefined,
|
|
105
|
+
"azp": undefined,
|
|
106
|
+
"email": undefined,
|
|
107
|
+
"exp": 1700000300,
|
|
108
|
+
"externalProvider": {
|
|
109
|
+
"aud": "client-1",
|
|
110
|
+
"exp": 1700000300,
|
|
111
|
+
"iat": 1700000000,
|
|
112
|
+
"iss": "http://auth.telicent.localhost",
|
|
113
|
+
"jti": "id-1",
|
|
114
|
+
"sub": "user-1",
|
|
115
|
+
},
|
|
116
|
+
"iat": 1700000000,
|
|
117
|
+
"isActive": undefined,
|
|
118
|
+
"iss": "http://auth.telicent.localhost",
|
|
119
|
+
"jti": "id-1",
|
|
120
|
+
"name": "user-1",
|
|
121
|
+
"nonce": undefined,
|
|
122
|
+
"preferred_name": undefined,
|
|
123
|
+
"sid": undefined,
|
|
124
|
+
"source": "id_token",
|
|
125
|
+
"sub": "user-1",
|
|
126
|
+
"token_expired": false,
|
|
127
|
+
"token_expires_at": "2023-11-14T22:18:20.000Z",
|
|
128
|
+
},
|
|
129
|
+
"warnings": [
|
|
130
|
+
"Returning unvalidated user info. Validation errors:",
|
|
131
|
+
],
|
|
132
|
+
}
|
|
133
|
+
`);
|
|
134
|
+
|
|
135
|
+
(Date.now as jest.Mock).mockRestore();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("returns null when decodeJWT throws", () => {
|
|
139
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
140
|
+
sessionStorage.setItem("auth_id_token", "TOKEN");
|
|
141
|
+
jest.spyOn(client, "decodeJWT").mockImplementation(() => {
|
|
142
|
+
throw new Error("decode failed");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const info = client.getUserInfo();
|
|
146
|
+
|
|
147
|
+
expect({ info }).toMatchInlineSnapshot(`
|
|
148
|
+
{
|
|
149
|
+
"info": null,
|
|
150
|
+
}
|
|
151
|
+
`);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import AuthServerOAuth2Client, {
|
|
2
|
+
AuthServerOAuth2ClientConfig,
|
|
3
|
+
} from "../../AuthServerOAuth2Client";
|
|
4
|
+
import { buildJwt, 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 - getUserInfo returns mapped user info", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
installTestEnv();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
resetTestEnv();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("returns user info for valid token", () => {
|
|
28
|
+
const now = 1_700_000_000_000;
|
|
29
|
+
jest.spyOn(Date, "now").mockReturnValue(now);
|
|
30
|
+
|
|
31
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
32
|
+
const token = buildJwt({
|
|
33
|
+
sub: "user-1",
|
|
34
|
+
aud: "client-1",
|
|
35
|
+
exp: Math.floor(now / 1000) + 300,
|
|
36
|
+
iat: Math.floor(now / 1000),
|
|
37
|
+
email: "user@example.com",
|
|
38
|
+
preferred_name: "User One",
|
|
39
|
+
iss: "http://auth.telicent.localhost",
|
|
40
|
+
jti: "id-1",
|
|
41
|
+
isActive: true,
|
|
42
|
+
});
|
|
43
|
+
sessionStorage.setItem("auth_id_token", token);
|
|
44
|
+
|
|
45
|
+
const info = client.getUserInfo();
|
|
46
|
+
|
|
47
|
+
expect({ info }).toMatchInlineSnapshot(`
|
|
48
|
+
{
|
|
49
|
+
"info": {
|
|
50
|
+
"aud": "client-1",
|
|
51
|
+
"auth_time": undefined,
|
|
52
|
+
"azp": undefined,
|
|
53
|
+
"email": "user@example.com",
|
|
54
|
+
"exp": 1700000300,
|
|
55
|
+
"externalProvider": {
|
|
56
|
+
"aud": "client-1",
|
|
57
|
+
"email": "user@example.com",
|
|
58
|
+
"exp": 1700000300,
|
|
59
|
+
"iat": 1700000000,
|
|
60
|
+
"isActive": true,
|
|
61
|
+
"iss": "http://auth.telicent.localhost",
|
|
62
|
+
"jti": "id-1",
|
|
63
|
+
"preferred_name": "User One",
|
|
64
|
+
"sub": "user-1",
|
|
65
|
+
},
|
|
66
|
+
"iat": 1700000000,
|
|
67
|
+
"isActive": true,
|
|
68
|
+
"iss": "http://auth.telicent.localhost",
|
|
69
|
+
"jti": "id-1",
|
|
70
|
+
"name": "User One",
|
|
71
|
+
"nonce": undefined,
|
|
72
|
+
"preferred_name": "User One",
|
|
73
|
+
"sid": undefined,
|
|
74
|
+
"source": "id_token",
|
|
75
|
+
"sub": "user-1",
|
|
76
|
+
"token_expired": false,
|
|
77
|
+
"token_expires_at": "2023-11-14T22:18:20.000Z",
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
`);
|
|
81
|
+
|
|
82
|
+
(Date.now as jest.Mock).mockRestore();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
const createFetchResponse = (options: { ok?: boolean }): Response =>
|
|
19
|
+
({
|
|
20
|
+
ok: options.ok ?? false,
|
|
21
|
+
json: jest.fn().mockResolvedValue({}),
|
|
22
|
+
} as unknown as Response);
|
|
23
|
+
|
|
24
|
+
describe("failure path - isAuthenticated errors", () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
installTestEnv();
|
|
27
|
+
setWindowLocation("http://app.telicent.localhost/home");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
resetTestEnv();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("returns false when response is not ok", async () => {
|
|
35
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
36
|
+
const fetchMock = jest.fn().mockResolvedValue(
|
|
37
|
+
createFetchResponse({ ok: false })
|
|
38
|
+
);
|
|
39
|
+
globalThis.fetch = fetchMock;
|
|
40
|
+
|
|
41
|
+
const result = await client.isAuthenticated();
|
|
42
|
+
|
|
43
|
+
expect({ result }).toMatchInlineSnapshot(`
|
|
44
|
+
{
|
|
45
|
+
"result": false,
|
|
46
|
+
}
|
|
47
|
+
`);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("returns false when fetch throws", async () => {
|
|
51
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
52
|
+
globalThis.fetch = jest.fn().mockRejectedValue(new Error("network"));
|
|
53
|
+
|
|
54
|
+
const result = await client.isAuthenticated();
|
|
55
|
+
|
|
56
|
+
expect({ result }).toMatchInlineSnapshot(`
|
|
57
|
+
{
|
|
58
|
+
"result": false,
|
|
59
|
+
}
|
|
60
|
+
`);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
+
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 - isAuthenticated succeeds", () => {
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
installTestEnv();
|
|
30
|
+
setWindowLocation("http://app.telicent.localhost/home");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
resetTestEnv();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("returns true and stores id token", async () => {
|
|
38
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
39
|
+
const fetchMock = jest.fn().mockResolvedValue(
|
|
40
|
+
createFetchResponse({ jsonData: { id_token: "ID_TOKEN_1" } })
|
|
41
|
+
);
|
|
42
|
+
globalThis.fetch = fetchMock;
|
|
43
|
+
|
|
44
|
+
const result = await client.isAuthenticated();
|
|
45
|
+
|
|
46
|
+
expect({
|
|
47
|
+
result,
|
|
48
|
+
authIdToken: sessionStorage.getItem("auth_id_token"),
|
|
49
|
+
fetchUrl: fetchMock.mock.calls[0][0],
|
|
50
|
+
}).toMatchInlineSnapshot(`
|
|
51
|
+
{
|
|
52
|
+
"authIdToken": "ID_TOKEN_1",
|
|
53
|
+
"fetchUrl": "http://auth.telicent.localhost/session/check",
|
|
54
|
+
"result": true,
|
|
55
|
+
}
|
|
56
|
+
`);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("sends Authorization header for cross-domain session", async () => {
|
|
60
|
+
const client = new AuthServerOAuth2Client(
|
|
61
|
+
createConfig({ authServerUrl: "https://auth.telicent.io" })
|
|
62
|
+
);
|
|
63
|
+
sessionStorage.setItem("auth_session_id", "SESSION_ABC");
|
|
64
|
+
const fetchMock = jest.fn().mockResolvedValue(
|
|
65
|
+
createFetchResponse({ jsonData: { id_token: "ID_TOKEN_2" } })
|
|
66
|
+
);
|
|
67
|
+
globalThis.fetch = fetchMock;
|
|
68
|
+
|
|
69
|
+
const result = await client.isAuthenticated();
|
|
70
|
+
|
|
71
|
+
expect({
|
|
72
|
+
result,
|
|
73
|
+
headers: fetchMock.mock.calls[0][1]?.headers,
|
|
74
|
+
}).toMatchInlineSnapshot(`
|
|
75
|
+
{
|
|
76
|
+
"headers": {
|
|
77
|
+
"Accept": "application/json",
|
|
78
|
+
"Authorization": "Bearer SESSION_ABC",
|
|
79
|
+
},
|
|
80
|
+
"result": true,
|
|
81
|
+
}
|
|
82
|
+
`);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import AuthServerOAuth2Client, {
|
|
2
|
+
AuthServerOAuth2ClientConfig,
|
|
3
|
+
} from "../../AuthServerOAuth2Client";
|
|
4
|
+
import { buildJwt, 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("failure path - isIdTokenExpired errors", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
installTestEnv();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
resetTestEnv();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("returns true when token is missing", () => {
|
|
28
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
29
|
+
|
|
30
|
+
const result = client.isIdTokenExpired();
|
|
31
|
+
|
|
32
|
+
expect({ result }).toMatchInlineSnapshot(`
|
|
33
|
+
{
|
|
34
|
+
"result": true,
|
|
35
|
+
}
|
|
36
|
+
`);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("returns true for expired token", () => {
|
|
40
|
+
const now = 1_700_000_000_000;
|
|
41
|
+
jest.spyOn(Date, "now").mockReturnValue(now);
|
|
42
|
+
|
|
43
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
44
|
+
const token = buildJwt({
|
|
45
|
+
sub: "user-1",
|
|
46
|
+
aud: "client-1",
|
|
47
|
+
exp: Math.floor(now / 1000) - 10,
|
|
48
|
+
});
|
|
49
|
+
sessionStorage.setItem("auth_id_token", token);
|
|
50
|
+
|
|
51
|
+
const result = client.isIdTokenExpired();
|
|
52
|
+
|
|
53
|
+
expect({ result }).toMatchInlineSnapshot(`
|
|
54
|
+
{
|
|
55
|
+
"result": true,
|
|
56
|
+
}
|
|
57
|
+
`);
|
|
58
|
+
|
|
59
|
+
(Date.now as jest.Mock).mockRestore();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("returns true when decodeJWT throws", () => {
|
|
63
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
64
|
+
sessionStorage.setItem("auth_id_token", "TOKEN");
|
|
65
|
+
jest.spyOn(client, "decodeJWT").mockImplementation(() => {
|
|
66
|
+
throw new Error("decode failed");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const result = client.isIdTokenExpired();
|
|
70
|
+
|
|
71
|
+
expect({ result }).toMatchInlineSnapshot(`
|
|
72
|
+
{
|
|
73
|
+
"result": true,
|
|
74
|
+
}
|
|
75
|
+
`);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import AuthServerOAuth2Client, {
|
|
2
|
+
AuthServerOAuth2ClientConfig,
|
|
3
|
+
} from "../../AuthServerOAuth2Client";
|
|
4
|
+
import { buildJwt, 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 - isIdTokenExpired returns false", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
installTestEnv();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
resetTestEnv();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("returns false for valid token", () => {
|
|
28
|
+
const now = 1_700_000_000_000;
|
|
29
|
+
jest.spyOn(Date, "now").mockReturnValue(now);
|
|
30
|
+
|
|
31
|
+
const client = new AuthServerOAuth2Client(createConfig());
|
|
32
|
+
const token = buildJwt({
|
|
33
|
+
sub: "user-1",
|
|
34
|
+
aud: "client-1",
|
|
35
|
+
exp: Math.floor(now / 1000) + 300,
|
|
36
|
+
});
|
|
37
|
+
sessionStorage.setItem("auth_id_token", token);
|
|
38
|
+
|
|
39
|
+
const result = client.isIdTokenExpired();
|
|
40
|
+
|
|
41
|
+
expect({ result }).toMatchInlineSnapshot(`
|
|
42
|
+
{
|
|
43
|
+
"result": false,
|
|
44
|
+
}
|
|
45
|
+
`);
|
|
46
|
+
|
|
47
|
+
(Date.now as jest.Mock).mockRestore();
|
|
48
|
+
});
|
|
49
|
+
});
|