@palantir/pack.auth 0.0.1-beta.1
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/.turbo/turbo-lint.log +42 -0
- package/.turbo/turbo-transpileBrowser.log +5 -0
- package/.turbo/turbo-transpileCjs.log +5 -0
- package/.turbo/turbo-transpileEsm.log +5 -0
- package/.turbo/turbo-transpileTypes.log +5 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/LICENSE.txt +13 -0
- package/README.md +105 -0
- package/build/browser/index.js +155 -0
- package/build/browser/index.js.map +1 -0
- package/build/cjs/index.cjs +163 -0
- package/build/cjs/index.cjs.map +1 -0
- package/build/cjs/index.d.cts +189 -0
- package/build/esm/index.js +155 -0
- package/build/esm/index.js.map +1 -0
- package/build/types/__tests__/AuthModuleImpl.test.d.ts +1 -0
- package/build/types/__tests__/AuthModuleImpl.test.d.ts.map +1 -0
- package/build/types/constants/AuthModuleKey.d.ts +4 -0
- package/build/types/constants/AuthModuleKey.d.ts.map +1 -0
- package/build/types/index.d.ts +11 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/types/AuthModule.d.ts +82 -0
- package/build/types/types/AuthModule.d.ts.map +1 -0
- package/build/types/types/AuthState.d.ts +14 -0
- package/build/types/types/AuthState.d.ts.map +1 -0
- package/build/types/types/BaseAuthService.d.ts +22 -0
- package/build/types/types/BaseAuthService.d.ts.map +1 -0
- package/build/types/types/TokenChange.d.ts +5 -0
- package/build/types/types/TokenChange.d.ts.map +1 -0
- package/build/types/types/UnverifiedTokenInfo.d.ts +13 -0
- package/build/types/types/UnverifiedTokenInfo.d.ts.map +1 -0
- package/build/types/types/UserRef.d.ts +21 -0
- package/build/types/types/UserRef.d.ts.map +1 -0
- package/build/types/utils/AuthModuleConfig.d.ts +16 -0
- package/build/types/utils/AuthModuleConfig.d.ts.map +1 -0
- package/build/types/utils/AuthModuleImpl.d.ts +25 -0
- package/build/types/utils/AuthModuleImpl.d.ts.map +1 -0
- package/package.json +67 -0
- package/src/__tests__/AuthModuleImpl.test.ts +249 -0
- package/src/constants/AuthModuleKey.ts +31 -0
- package/src/index.ts +27 -0
- package/src/types/AuthModule.ts +117 -0
- package/src/types/AuthState.ts +33 -0
- package/src/types/BaseAuthService.ts +39 -0
- package/src/types/TokenChange.ts +25 -0
- package/src/types/UnverifiedTokenInfo.ts +30 -0
- package/src/types/UserRef.ts +77 -0
- package/src/utils/AuthModuleConfig.ts +40 -0
- package/src/utils/AuthModuleImpl.ts +124 -0
- package/tsconfig.json +21 -0
- package/vitest.config.mjs +26 -0
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@palantir/pack.auth",
|
|
3
|
+
"version": "0.0.1-beta.1",
|
|
4
|
+
"description": "Authentication system for PACK applications",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/palantir/pack.git"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"browser": "./build/browser/index.js",
|
|
13
|
+
"import": {
|
|
14
|
+
"types": "./build/types/index.d.ts",
|
|
15
|
+
"default": "./build/esm/index.js"
|
|
16
|
+
},
|
|
17
|
+
"require": "./build/cjs/index.js",
|
|
18
|
+
"default": "./build/browser/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./*": {
|
|
21
|
+
"browser": "./build/browser/public/*.js",
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./build/types/public/*.d.ts",
|
|
24
|
+
"default": "./build/js/public/*.js"
|
|
25
|
+
},
|
|
26
|
+
"require": "./build/cjs/public/*.js",
|
|
27
|
+
"default": "./build/browser/public/*.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"tiny-invariant": "^1.3.3",
|
|
32
|
+
"@palantir/pack.core": "0.1.0-beta.2"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@osdk/client": "~2.4.2"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"rimraf": "^6.0.1",
|
|
39
|
+
"tslib": "^2.8.1",
|
|
40
|
+
"typescript": "^5.9.2",
|
|
41
|
+
"vitest-mock-extended": "^3.1.0",
|
|
42
|
+
"@palantir/pack.monorepo.tsconfig": "~0.4.0-beta.1"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"pack",
|
|
49
|
+
"auth"
|
|
50
|
+
],
|
|
51
|
+
"main": "./build/cjs/index.js",
|
|
52
|
+
"module": "./build/esm/index.js",
|
|
53
|
+
"types": "./build/cjs/index.d.ts",
|
|
54
|
+
"type": "module",
|
|
55
|
+
"scripts": {
|
|
56
|
+
"clean": "rimraf .turbo build dist lib test-output *.tgz tsconfig.tsbuildinfo",
|
|
57
|
+
"lint": "eslint ./src ; dprint check --config $(find-up dprint.json) --allow-no-files",
|
|
58
|
+
"lint:fix": "eslint ./src --fix ; dprint fmt --config $(find-up dprint.json) --allow-no-files",
|
|
59
|
+
"test": "vitest run --passWithNoTests -u",
|
|
60
|
+
"test:watch": "vitest --passWithNoTests",
|
|
61
|
+
"transpileBrowser": "monorepo-transpile -f esm -m bundle -t browser",
|
|
62
|
+
"transpileCjs": "monorepo-transpile -f cjs -m bundle -t node",
|
|
63
|
+
"transpileEsm": "monorepo-transpile -f esm -m bundle -t node",
|
|
64
|
+
"transpileTypes": "monorepo-transpile -f esm -m types -t node",
|
|
65
|
+
"typecheck": "tsc --noEmit --emitDeclarationOnly false"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { PackAppInternal } from "@palantir/pack.core";
|
|
18
|
+
import type { MockedObject } from "vitest";
|
|
19
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
20
|
+
import { mockDeep } from "vitest-mock-extended";
|
|
21
|
+
import { AuthModuleImpl, AuthState, type AuthStateCallback } from "../index.js";
|
|
22
|
+
import type { BaseAuthService } from "../types/BaseAuthService.js";
|
|
23
|
+
|
|
24
|
+
function createMockAuthService(
|
|
25
|
+
tokenValue = "mock-token",
|
|
26
|
+
overrides: Partial<BaseAuthService> = {},
|
|
27
|
+
): MockedObject<BaseAuthService> {
|
|
28
|
+
const defaultService = {
|
|
29
|
+
dispose: vi.fn(),
|
|
30
|
+
getCurrentState: vi.fn().mockReturnValue(AuthState.Unauthenticated),
|
|
31
|
+
getCurrentUserId: vi.fn().mockReturnValue(undefined),
|
|
32
|
+
getToken: vi.fn().mockResolvedValue(tokenValue),
|
|
33
|
+
getTokenOrUndefined: vi.fn().mockReturnValue(undefined),
|
|
34
|
+
getUserData: vi.fn().mockResolvedValue({}),
|
|
35
|
+
isAuthenticated: vi.fn().mockReturnValue(false),
|
|
36
|
+
isValidated: vi.fn().mockReturnValue(false),
|
|
37
|
+
onAuthStateChange: vi.fn().mockReturnValue(vi.fn()),
|
|
38
|
+
refresh: vi.fn().mockResolvedValue(undefined),
|
|
39
|
+
signIn: vi.fn().mockResolvedValue(undefined),
|
|
40
|
+
signOut: vi.fn().mockResolvedValue(undefined),
|
|
41
|
+
validateToken: vi.fn().mockResolvedValue(true),
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return defaultService as MockedObject<BaseAuthService>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
describe("AuthModuleImpl", () => {
|
|
49
|
+
let authModule: AuthModuleImpl;
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
authModule.dispose();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("with static token service", () => {
|
|
56
|
+
let authService: BaseAuthService;
|
|
57
|
+
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
// Create mock service that behaves like static token service
|
|
60
|
+
authService = createMockAuthService("static-token", {
|
|
61
|
+
isAuthenticated: vi.fn().mockReturnValue(true), // Static services start authenticated
|
|
62
|
+
signOut: vi.fn().mockRejectedValue(
|
|
63
|
+
new Error("Sign out not supported for static token providers"),
|
|
64
|
+
),
|
|
65
|
+
refresh: undefined, // Static services don't support refresh
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const mockApp = mockDeep<PackAppInternal>();
|
|
69
|
+
|
|
70
|
+
authModule = new AuthModuleImpl(mockApp, authService);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should be authenticated immediately", () => {
|
|
74
|
+
expect(authModule.isAuthenticated()).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should return token from provider", async () => {
|
|
78
|
+
const token = await authModule.getToken();
|
|
79
|
+
expect(token).toBe("static-token");
|
|
80
|
+
expect(authService.getToken).toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should return undefined for getTokenOrUndefined initially", () => {
|
|
84
|
+
expect(authModule.getTokenOrUndefined()).toBeUndefined();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should be no-op for signIn", async () => {
|
|
88
|
+
await expect(authModule.signIn()).resolves.toBeUndefined();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should reject signOut for static token providers", async () => {
|
|
92
|
+
await expect(authModule.signOut()).rejects.toThrow(
|
|
93
|
+
"Sign out not supported for static token providers",
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should throw for refresh", async () => {
|
|
98
|
+
await expect(authModule.refresh()).rejects.toThrow("Refresh not supported");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should allow state change subscriptions", () => {
|
|
102
|
+
const callback = vi.fn();
|
|
103
|
+
const unsubscribe = authModule.onAuthStateChange(callback);
|
|
104
|
+
|
|
105
|
+
expect(typeof unsubscribe).toBe("function");
|
|
106
|
+
unsubscribe();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should resolve waitForAuth immediately when already authenticated", async () => {
|
|
110
|
+
await expect(authModule.waitForAuth()).resolves.toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("with OAuth service", () => {
|
|
115
|
+
let mockApp: ReturnType<typeof mockDeep<PackAppInternal>>;
|
|
116
|
+
let mockAuthService: MockedObject<BaseAuthService>;
|
|
117
|
+
|
|
118
|
+
beforeEach(() => {
|
|
119
|
+
mockAuthService = createMockAuthService("oauth-token");
|
|
120
|
+
mockApp = mockDeep<PackAppInternal>();
|
|
121
|
+
|
|
122
|
+
authModule = new AuthModuleImpl(mockApp, mockAuthService);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should delegate isAuthenticated to service", () => {
|
|
126
|
+
expect(authModule.isAuthenticated()).toBe(false);
|
|
127
|
+
expect(mockAuthService.isAuthenticated).toHaveBeenCalled();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("should delegate getToken to service", async () => {
|
|
131
|
+
const token = await authModule.getToken();
|
|
132
|
+
expect(token).toBe("oauth-token");
|
|
133
|
+
expect(mockAuthService.getToken).toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("should delegate getTokenOrUndefined to service", () => {
|
|
137
|
+
const token = authModule.getTokenOrUndefined();
|
|
138
|
+
expect(token).toBeUndefined();
|
|
139
|
+
expect(mockAuthService.getTokenOrUndefined).toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should delegate signIn to service", async () => {
|
|
143
|
+
await authModule.signIn();
|
|
144
|
+
expect(mockAuthService.signIn).toHaveBeenCalled();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("should delegate signOut to service", async () => {
|
|
148
|
+
await authModule.signOut();
|
|
149
|
+
expect(mockAuthService.signOut).toHaveBeenCalled();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("should delegate refresh to service", async () => {
|
|
153
|
+
await authModule.refresh();
|
|
154
|
+
expect(mockAuthService.refresh).toHaveBeenCalled();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("should delegate onAuthStateChange to service", () => {
|
|
158
|
+
const callback = vi.fn();
|
|
159
|
+
authModule.onAuthStateChange(callback);
|
|
160
|
+
expect(mockAuthService.onAuthStateChange).toHaveBeenCalledWith(callback);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe("waitForAuth behavior", () => {
|
|
165
|
+
it("should resolve immediately when already authenticated", async () => {
|
|
166
|
+
const mockAuthService = createMockAuthService("test-token", {
|
|
167
|
+
isAuthenticated: vi.fn().mockReturnValue(true),
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const mockApp = mockDeep<PackAppInternal>();
|
|
171
|
+
|
|
172
|
+
authModule = new AuthModuleImpl(mockApp, mockAuthService);
|
|
173
|
+
|
|
174
|
+
await expect(authModule.waitForAuth()).resolves.toBeUndefined();
|
|
175
|
+
expect(mockAuthService.onAuthStateChange).not.toHaveBeenCalled();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("should wait for authentication event when not authenticated", async () => {
|
|
179
|
+
const mockUnsubscribe = vi.fn();
|
|
180
|
+
const mockAuthService = createMockAuthService("test-token", {
|
|
181
|
+
isAuthenticated: vi.fn().mockReturnValue(false),
|
|
182
|
+
onAuthStateChange: vi.fn().mockImplementation((callback: AuthStateCallback) => {
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
callback({
|
|
185
|
+
state: AuthState.Authenticated,
|
|
186
|
+
previousState: AuthState.Unauthenticated,
|
|
187
|
+
});
|
|
188
|
+
}, 10);
|
|
189
|
+
return mockUnsubscribe;
|
|
190
|
+
}),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const mockApp = mockDeep<PackAppInternal>();
|
|
194
|
+
|
|
195
|
+
authModule = new AuthModuleImpl(mockApp, mockAuthService);
|
|
196
|
+
|
|
197
|
+
await expect(authModule.waitForAuth()).resolves.toBeUndefined();
|
|
198
|
+
expect(mockAuthService.onAuthStateChange).toHaveBeenCalled();
|
|
199
|
+
expect(mockUnsubscribe).toHaveBeenCalled();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should reject on authentication error", async () => {
|
|
203
|
+
const mockUnsubscribe = vi.fn();
|
|
204
|
+
const error = new Error("Auth failed");
|
|
205
|
+
const mockAuthService = createMockAuthService("test-token", {
|
|
206
|
+
isAuthenticated: vi.fn().mockReturnValue(false),
|
|
207
|
+
onAuthStateChange: vi.fn().mockImplementation((callback: AuthStateCallback) => {
|
|
208
|
+
setTimeout(() => {
|
|
209
|
+
callback({
|
|
210
|
+
state: AuthState.Error,
|
|
211
|
+
previousState: AuthState.Authenticating,
|
|
212
|
+
error,
|
|
213
|
+
});
|
|
214
|
+
}, 10);
|
|
215
|
+
return mockUnsubscribe;
|
|
216
|
+
}),
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const mockApp = mockDeep<PackAppInternal>();
|
|
220
|
+
|
|
221
|
+
authModule = new AuthModuleImpl(mockApp, mockAuthService);
|
|
222
|
+
|
|
223
|
+
await expect(authModule.waitForAuth()).rejects.toThrow("Authentication failed");
|
|
224
|
+
expect(mockUnsubscribe).toHaveBeenCalled();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe("signIn deduplication", () => {
|
|
229
|
+
it("should deduplicate concurrent signIn calls", async () => {
|
|
230
|
+
const mockAuthService = createMockAuthService("test-token", {
|
|
231
|
+
signIn: vi.fn().mockImplementation(() => new Promise(resolve => setTimeout(resolve, 50))),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const mockApp = mockDeep<PackAppInternal>();
|
|
235
|
+
|
|
236
|
+
authModule = new AuthModuleImpl(mockApp, mockAuthService);
|
|
237
|
+
|
|
238
|
+
const promises = [
|
|
239
|
+
authModule.signIn(),
|
|
240
|
+
authModule.signIn(),
|
|
241
|
+
authModule.signIn(),
|
|
242
|
+
];
|
|
243
|
+
|
|
244
|
+
await Promise.all(promises);
|
|
245
|
+
|
|
246
|
+
expect(mockAuthService.signIn).toHaveBeenCalledTimes(1);
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { ModuleKey, PackAppInternal } from "@palantir/pack.core";
|
|
18
|
+
import type { AuthModule } from "../types/AuthModule.js";
|
|
19
|
+
import type { AuthModuleConfig } from "../utils/AuthModuleConfig.js";
|
|
20
|
+
import { AuthModuleImpl } from "../utils/AuthModuleImpl.js";
|
|
21
|
+
|
|
22
|
+
export const AUTH_MODULE_KEY: ModuleKey<AuthModule, AuthModuleConfig> = {
|
|
23
|
+
appMemberName: "auth",
|
|
24
|
+
key: Symbol.for("pack.auth"),
|
|
25
|
+
initModule: (app: PackAppInternal, config?: AuthModuleConfig) => {
|
|
26
|
+
if (!config) {
|
|
27
|
+
throw new Error("AuthModuleConfig is required to initialize AuthModule");
|
|
28
|
+
}
|
|
29
|
+
return new AuthModuleImpl(app, config.authService);
|
|
30
|
+
},
|
|
31
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export { getAuthModule } from "./types/AuthModule.js";
|
|
18
|
+
export type { AuthModule } from "./types/AuthModule.js";
|
|
19
|
+
export { AuthState } from "./types/AuthState.js";
|
|
20
|
+
export type { AuthStateCallback, AuthStateChangeEvent } from "./types/AuthState.js";
|
|
21
|
+
export type { BaseAuthService } from "./types/BaseAuthService.js";
|
|
22
|
+
export type { TokenChangeCallback } from "./types/TokenChange.js";
|
|
23
|
+
export type { UnverifiedTokenInfo } from "./types/UnverifiedTokenInfo.js";
|
|
24
|
+
export { createUserRef, invalidUserRef, isValidUserRef } from "./types/UserRef.js";
|
|
25
|
+
export type { UserId, UserRef } from "./types/UserRef.js";
|
|
26
|
+
export { type AuthModuleConfig, createAuthModuleConfig } from "./utils/AuthModuleConfig.js";
|
|
27
|
+
export { AuthModuleImpl } from "./utils/AuthModuleImpl.js";
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { PackAppInternal, Unsubscribe } from "@palantir/pack.core";
|
|
18
|
+
import { assertIsAppInternal } from "@palantir/pack.core";
|
|
19
|
+
import { AUTH_MODULE_KEY } from "../constants/AuthModuleKey.js";
|
|
20
|
+
import type { AuthStateCallback } from "./AuthState.js";
|
|
21
|
+
import type { TokenChangeCallback } from "./TokenChange.js";
|
|
22
|
+
import type { UserRef } from "./UserRef.js";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* AuthModule provides unified authentication services for PACK applications.
|
|
26
|
+
*
|
|
27
|
+
* It wraps OSDK OAuth clients and provides a consistent interface for authentication
|
|
28
|
+
* state management, token access, and auth lifecycle events.
|
|
29
|
+
*/
|
|
30
|
+
// TODO: functions should be method style
|
|
31
|
+
export interface AuthModule {
|
|
32
|
+
/**
|
|
33
|
+
* Get the current user information.
|
|
34
|
+
* Returns undefined if not authenticated or user data not available.
|
|
35
|
+
*/
|
|
36
|
+
readonly getCurrentUser: () => UserRef | undefined;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get an access token, automatically refreshing if needed.
|
|
40
|
+
* Throws if authentication fails or user is not signed in.
|
|
41
|
+
*/
|
|
42
|
+
readonly getToken: () => Promise<string>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get the current access token without refresh, returns undefined if expired or unavailable.
|
|
46
|
+
*/
|
|
47
|
+
readonly getTokenOrUndefined: () => string | undefined;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get user data for a specific user ID.
|
|
51
|
+
* @param userId - The user ID to fetch data for
|
|
52
|
+
* @param force - Force refresh of cached data
|
|
53
|
+
* @returns Promise resolving to user data
|
|
54
|
+
*/
|
|
55
|
+
readonly getUserData: (userId: string, force?: boolean) => Promise<unknown>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check if the user is currently authenticated with a valid token.
|
|
59
|
+
*/
|
|
60
|
+
readonly isAuthenticated: () => boolean;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Subscribe to authentication state changes.
|
|
64
|
+
*
|
|
65
|
+
* @param callback Function called when auth state changes
|
|
66
|
+
* @returns Unsubscribe function
|
|
67
|
+
*/
|
|
68
|
+
readonly onAuthStateChange: (callback: AuthStateCallback) => Unsubscribe;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Subscribe to token changes.
|
|
72
|
+
*
|
|
73
|
+
* @param callback Function called when token changes
|
|
74
|
+
* @returns Unsubscribe function
|
|
75
|
+
*/
|
|
76
|
+
readonly onTokenChange: (callback: TokenChangeCallback) => Unsubscribe;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Manually refresh the access token using the refresh token.
|
|
80
|
+
* Only available for public OAuth clients.
|
|
81
|
+
*/
|
|
82
|
+
readonly refresh?: () => Promise<void>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Initiate sign-in flow. For public clients, this redirects to OAuth.
|
|
86
|
+
* For confidential clients, this performs client credentials flow.
|
|
87
|
+
*/
|
|
88
|
+
readonly signIn: () => Promise<void>;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Sign out the current user and clear tokens.
|
|
92
|
+
*/
|
|
93
|
+
readonly signOut: () => Promise<void>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Validate the current token by checking with the platform API.
|
|
97
|
+
* Returns true if the token is valid, false otherwise.
|
|
98
|
+
*/
|
|
99
|
+
readonly validateToken: () => Promise<boolean>;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Wait for authentication to complete. Resolves when authenticated,
|
|
103
|
+
* rejects if authentication fails or times out.
|
|
104
|
+
*/
|
|
105
|
+
readonly waitForAuth: () => Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get the auth module from an PACK app instance.
|
|
110
|
+
*
|
|
111
|
+
* @param app - PACK app instance
|
|
112
|
+
* @returns The auth module
|
|
113
|
+
*/
|
|
114
|
+
export function getAuthModule(app: PackAppInternal): AuthModule {
|
|
115
|
+
assertIsAppInternal(app);
|
|
116
|
+
return app.getModule(AUTH_MODULE_KEY);
|
|
117
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export const AuthState = {
|
|
18
|
+
Authenticated: "authenticated",
|
|
19
|
+
Authenticating: "authenticating",
|
|
20
|
+
Error: "error",
|
|
21
|
+
Initializing: "initializing",
|
|
22
|
+
Unauthenticated: "unauthenticated",
|
|
23
|
+
} as const;
|
|
24
|
+
|
|
25
|
+
export type AuthState = typeof AuthState[keyof typeof AuthState];
|
|
26
|
+
|
|
27
|
+
export interface AuthStateChangeEvent {
|
|
28
|
+
readonly previousState?: AuthState;
|
|
29
|
+
readonly state: AuthState;
|
|
30
|
+
readonly error?: Error;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type AuthStateCallback = (event: AuthStateChangeEvent) => void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { Unsubscribe } from "@palantir/pack.core";
|
|
18
|
+
import type { AuthState, AuthStateCallback } from "./AuthState.js";
|
|
19
|
+
import type { TokenChangeCallback } from "./TokenChange.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Base interface for auth services that wrap different OAuth client implementations
|
|
23
|
+
*/
|
|
24
|
+
export interface BaseAuthService {
|
|
25
|
+
dispose(): void;
|
|
26
|
+
getCurrentState(): AuthState;
|
|
27
|
+
getCurrentUserId(): string | undefined;
|
|
28
|
+
getToken(): Promise<string>;
|
|
29
|
+
getTokenOrUndefined(): string | undefined;
|
|
30
|
+
getUserData(userId: string, force?: boolean): Promise<unknown>;
|
|
31
|
+
isAuthenticated(): boolean;
|
|
32
|
+
isValidated(): boolean;
|
|
33
|
+
onAuthStateChange(callback: AuthStateCallback): Unsubscribe;
|
|
34
|
+
onTokenChange(callback: TokenChangeCallback): Unsubscribe;
|
|
35
|
+
refresh?(): Promise<void>;
|
|
36
|
+
signIn(): Promise<void>;
|
|
37
|
+
signOut(): Promise<void>;
|
|
38
|
+
validateToken(): Promise<boolean>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { UnverifiedTokenInfo } from "./UnverifiedTokenInfo.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Callback function for token change events. A signout may fire a token change with undefined token.
|
|
21
|
+
*/
|
|
22
|
+
export type TokenChangeCallback = (
|
|
23
|
+
token: string | undefined,
|
|
24
|
+
info: UnverifiedTokenInfo,
|
|
25
|
+
) => void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { UserId } from "./UserRef.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents the parsed payload from a JWT token (unverified).
|
|
21
|
+
* The information provided should not be used for security-sensitive
|
|
22
|
+
* applications unless verified through some other process.
|
|
23
|
+
*/
|
|
24
|
+
export interface UnverifiedTokenInfo {
|
|
25
|
+
readonly expiryInstantUtc?: number;
|
|
26
|
+
readonly orgId?: string;
|
|
27
|
+
readonly sessionId?: string;
|
|
28
|
+
readonly tokenId?: string;
|
|
29
|
+
readonly userId?: UserId;
|
|
30
|
+
}
|