@idp.global/sdk 17.0.0 → 18.0.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/changelog.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-09-19 - 18.0.0
4
+
5
+ ### Breaking Changes
6
+
7
+ - move the server account store from `@push.rocks/smartdata` to `@lossless.org/client/nosqldb` (persistence)
8
+ - Removes the `@push.rocks/smartdata` dependency and adds a required peer dependency `@lossless.org/client` (`>=1.0.0 <2.0.0`). Consumers of `@idp.global/sdk/server` must install it themselves; the subpath imports it statically, so every `./server` import fails without it.
9
+ - `SmartdataAccountStore({ smartdataDb })` and `setAccountDocSmartdataDb()` now take the `SmartdataDb` exported by `@lossless.org/client/nosqldb`. A `SmartdataDb` built by `@push.rocks/smartdata` is no longer accepted: it is a different class identity and both the type check and the model's runtime db resolution reject it.
10
+ - The store, the document class and the scrypt password hasher are otherwise unchanged. Stored accounts are not transformed: the collection stays `IdpSdkAccountDoc`, `_id` stays a mongo ObjectId distinct from the application `id`, the `_id_` and unique `id_1` indexes are unchanged, and the persisted field set, field types and `scrypt:v1` hash format are asserted verbatim in `test/test.account-store-persistence.node.ts`.
11
+
12
+
13
+ ### Fixes
14
+
15
+ - upgrade release tooling to the current published versions (deps-dev)
16
+ - pnpm 12.3.4 -> 12.4.1, `@git.zone/tsbuild` ^4.4.2 -> ^4.5.0, `@git.zone/tstest` ^6.0.0 -> ^6.1.1, `@types/node` 26.4.1 -> 26.5.1.
17
+
18
+ ## 2026-09-13 - 17.1.0
19
+
20
+ ### Fixes
21
+
22
+ - Update release tooling, require build and test preflight, and qualify account persistence against NoSQLDB 10.2.0.
23
+
24
+ ### Features
25
+
26
+ - Add a subject-bound server UserInfo client with bounded transport and validated organization display claims.
27
+
3
28
  ## 2026-09-09 - 17.0.0
4
29
 
5
30
  ### Breaking Changes
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@idp.global/sdk',
6
- version: '17.0.0',
6
+ version: '18.0.0',
7
7
  description: 'Reusable browser and server SDK for idp.global authentication.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxpQkFBaUI7SUFDdkIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLGdFQUFnRTtDQUM5RSxDQUFBIn0=
@@ -1,7 +1,7 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import type { IIdpSdkAccount, TIdpAccountAuthSource, TIdpAccountRole, TIdpAccountStatus } from './interfaces.js';
3
- export declare const setAccountDocSmartdataDb: (smartdataDbArg: plugins.smartdata.SmartdataDb) => void;
4
- export declare class IdpSdkAccountDoc extends plugins.smartdata.SmartDataDbDoc<IdpSdkAccountDoc, IdpSdkAccountDoc> {
3
+ export declare const setAccountDocSmartdataDb: (smartdataDbArg: plugins.nosqldb.SmartdataDb) => void;
4
+ export declare class IdpSdkAccountDoc extends plugins.nosqldb.SmartDataDbDoc<IdpSdkAccountDoc, IdpSdkAccountDoc> {
5
5
  id: string;
6
6
  email: string;
7
7
  emailNormalized: string;
@@ -44,11 +44,11 @@ const getDb = () => {
44
44
  return activeSmartdataDb;
45
45
  };
46
46
  let IdpSdkAccountDoc = (() => {
47
- let _classDecorators = [plugins.smartdata.Collection(() => getDb())];
47
+ let _classDecorators = [plugins.nosqldb.Collection(() => getDb())];
48
48
  let _classDescriptor;
49
49
  let _classExtraInitializers = [];
50
50
  let _classThis;
51
- let _classSuper = plugins.smartdata.SmartDataDbDoc;
51
+ let _classSuper = plugins.nosqldb.SmartDataDbDoc;
52
52
  let _id_decorators;
53
53
  let _id_initializers = [];
54
54
  let _id_extraInitializers = [];
@@ -89,18 +89,18 @@ let IdpSdkAccountDoc = (() => {
89
89
  static { _classThis = this; }
90
90
  static {
91
91
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
92
- _id_decorators = [plugins.smartdata.unI(), plugins.smartdata.svDb()];
93
- _email_decorators = [plugins.smartdata.svDb()];
94
- _emailNormalized_decorators = [plugins.smartdata.svDb()];
95
- _name_decorators = [plugins.smartdata.svDb()];
96
- _role_decorators = [plugins.smartdata.svDb()];
97
- _status_decorators = [plugins.smartdata.svDb()];
98
- _authSources_decorators = [plugins.smartdata.svDb()];
99
- _passwordHash_decorators = [plugins.smartdata.svDb()];
100
- _idpSubject_decorators = [plugins.smartdata.svDb()];
101
- _createdAt_decorators = [plugins.smartdata.svDb()];
102
- _updatedAt_decorators = [plugins.smartdata.svDb()];
103
- _lastLoginAt_decorators = [plugins.smartdata.svDb()];
92
+ _id_decorators = [plugins.nosqldb.unI(), plugins.nosqldb.svDb()];
93
+ _email_decorators = [plugins.nosqldb.svDb()];
94
+ _emailNormalized_decorators = [plugins.nosqldb.svDb()];
95
+ _name_decorators = [plugins.nosqldb.svDb()];
96
+ _role_decorators = [plugins.nosqldb.svDb()];
97
+ _status_decorators = [plugins.nosqldb.svDb()];
98
+ _authSources_decorators = [plugins.nosqldb.svDb()];
99
+ _passwordHash_decorators = [plugins.nosqldb.svDb()];
100
+ _idpSubject_decorators = [plugins.nosqldb.svDb()];
101
+ _createdAt_decorators = [plugins.nosqldb.svDb()];
102
+ _updatedAt_decorators = [plugins.nosqldb.svDb()];
103
+ _lastLoginAt_decorators = [plugins.nosqldb.svDb()];
104
104
  __esDecorate(null, null, _id_decorators, { kind: "field", name: "id", static: false, private: false, access: { has: obj => "id" in obj, get: obj => obj.id, set: (obj, value) => { obj.id = value; } }, metadata: _metadata }, _id_initializers, _id_extraInitializers);
105
105
  __esDecorate(null, null, _email_decorators, { kind: "field", name: "email", static: false, private: false, access: { has: obj => "email" in obj, get: obj => obj.email, set: (obj, value) => { obj.email = value; } }, metadata: _metadata }, _email_initializers, _email_extraInitializers);
106
106
  __esDecorate(null, null, _emailNormalized_decorators, { kind: "field", name: "emailNormalized", static: false, private: false, access: { has: obj => "emailNormalized" in obj, get: obj => obj.emailNormalized, set: (obj, value) => { obj.emailNormalized = value; } }, metadata: _metadata }, _emailNormalized_initializers, _emailNormalized_extraInitializers);
@@ -163,4 +163,4 @@ let IdpSdkAccountDoc = (() => {
163
163
  return IdpSdkAccountDoc = _classThis;
164
164
  })();
165
165
  export { IdpSdkAccountDoc };
166
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hY2NvdW50LWRvYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX3NlcnZlci9jbGFzc2VzLmFjY291bnQtZG9jLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUd4QyxJQUFJLGlCQUFpQixHQUF5QyxJQUFJLENBQUM7QUFFbkUsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsQ0FBQyxjQUE2QyxFQUFFLEVBQUU7SUFDeEYsaUJBQWlCLEdBQUcsY0FBYyxDQUFDO0FBQ3JDLENBQUMsQ0FBQztBQUVGLE1BQU0sS0FBSyxHQUFHLEdBQUcsRUFBRTtJQUNqQixJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNELE9BQU8saUJBQWlCLENBQUM7QUFDM0IsQ0FBQyxDQUFDO0lBR1csZ0JBQWdCOzRCQUQ1QixPQUFPLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLEVBQUUsQ0FBQzs7OztzQkFDTixPQUFPLENBQUMsU0FBUyxDQUFDLGNBQWM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Z0NBQXhDLFNBQVEsV0FBb0U7Ozs7OEJBQ3ZHLE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLEVBQ3ZCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFO2lDQUd4QixPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRTsyQ0FHeEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUU7Z0NBR3hCLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFO2dDQUd4QixPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRTtrQ0FHeEIsT0FBTyxDQUFDLFNB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
166
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hY2NvdW50LWRvYy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX3NlcnZlci9jbGFzc2VzLmFjY291bnQtZG9jLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUd4QyxJQUFJLGlCQUFpQixHQUF1QyxJQUFJLENBQUM7QUFFakUsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsQ0FBQyxjQUEyQyxFQUFFLEVBQUU7SUFDdEYsaUJBQWlCLEdBQUcsY0FBYyxDQUFDO0FBQ3JDLENBQUMsQ0FBQztBQUVGLE1BQU0sS0FBSyxHQUFHLEdBQUcsRUFBRTtJQUNqQixJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLGdEQUFnRCxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNELE9BQU8saUJBQWlCLENBQUM7QUFDM0IsQ0FBQyxDQUFDO0lBR1csZ0JBQWdCOzRCQUQ1QixPQUFPLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLEVBQUUsQ0FBQzs7OztzQkFDSixPQUFPLENBQUMsT0FBTyxDQUFDLGNBQWM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Z0NBQXRDLFNBQVEsV0FBa0U7Ozs7OEJBQ3JHLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQ3JCLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFO2lDQUd0QixPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRTsyQ0FHdEIsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUU7Z0NBR3RCLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFO2dDQUd0QixPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRTtrQ0FHdEIsT0FBTyxDQUFDLE9B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
@@ -3,7 +3,7 @@ import type { ICreateIdpSdkAccountOptions, IIdpSdkAccount } from './interfaces.j
3
3
  export declare class SmartdataAccountStore {
4
4
  private optionsArg;
5
5
  constructor(optionsArg: {
6
- smartdataDb: plugins.smartdata.SmartdataDb;
6
+ smartdataDb: plugins.nosqldb.SmartdataDb;
7
7
  });
8
8
  normalizeEmail(emailArg: string): string;
9
9
  createAccount(optionsArg: ICreateIdpSdkAccountOptions): Promise<IIdpSdkAccount>;
@@ -81,4 +81,4 @@ export class SmartdataAccountStore {
81
81
  return [...new Set(authSourcesArg.filter((sourceArg) => sourceArg === 'local' || sourceArg === 'idp.global'))];
82
82
  }
83
83
  }
84
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hY2NvdW50LXN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfc2VydmVyL2NsYXNzZXMuYWNjb3VudC1zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN0RixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFHOUQsTUFBTSxPQUFPLHFCQUFxQjtJQUNaO0lBQXBCLFlBQW9CLFVBQTBEO1FBQTFELGVBQVUsR0FBVixVQUFVLENBQWdEO1FBQzVFLHdCQUF3QixDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRU0sY0FBYyxDQUFDLFFBQWdCO1FBQ3BDLE9BQU8sUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3ZDLENBQUM7SUFFTSxLQUFLLENBQUMsYUFBYSxDQUFDLFVBQXVDO1FBQ2hFLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlELElBQUksQ0FBQyxlQUFlLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdkQsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO1FBQ3ZELENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLGdCQUFnQixDQUFDLHFCQUFxQixDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQy9FLElBQUksUUFBUSxFQUFFLENBQUM7WUFDYixNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixlQUFlLEVBQUUsQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMs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
84
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5hY2NvdW50LXN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfc2VydmVyL2NsYXNzZXMuYWNjb3VudC1zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN0RixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFHOUQsTUFBTSxPQUFPLHFCQUFxQjtJQUNaO0lBQXBCLFlBQW9CLFVBQXdEO1FBQXhELGVBQVUsR0FBVixVQUFVLENBQThDO1FBQzFFLHdCQUF3QixDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRU0sY0FBYyxDQUFDLFFBQWdCO1FBQ3BDLE9BQU8sUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3ZDLENBQUM7SUFFTSxLQUFLLENBQUMsYUFBYSxDQUFDLFVBQXVDO1FBQ2hFLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlELElBQUksQ0FBQyxlQUFlLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdkQsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO1FBQ3ZELENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLGdCQUFnQixDQUFDLHFCQUFxQixDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQy9FLElBQUksUUFBUSxFQUFFLENBQUM7WUFDYixNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixlQUFlLEVBQUUsQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsb0JBQW9CLENBQUMs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
@@ -0,0 +1,22 @@
1
+ import * as plugins from './plugins.js';
2
+ export interface IOidcUserInfoClientOptions {
3
+ issuer: string;
4
+ timeoutMs?: number;
5
+ maxResponseBytes?: number;
6
+ }
7
+ export interface IOidcUserInfoClientRequest {
8
+ token: string;
9
+ /** Subject already established by the application's verified OIDC login. */
10
+ subject: string;
11
+ }
12
+ export declare class OidcUserInfoError extends Error {
13
+ readonly code: 'invalid_request' | 'invalid_response' | 'unauthenticated' | 'unavailable';
14
+ constructor(code: 'invalid_request' | 'invalid_response' | 'unauthenticated' | 'unavailable');
15
+ }
16
+ /** Fetches display claims using a server-held token; results are never authorization grants. */
17
+ export declare class OidcUserInfoClient {
18
+ #private;
19
+ constructor(optionsArg: IOidcUserInfoClientOptions);
20
+ getUserInfo(requestArg: IOidcUserInfoClientRequest): Promise<plugins.idpInterfaces.data.IUserInfoResponse>;
21
+ private validateResponse;
22
+ }
@@ -0,0 +1,154 @@
1
+ import * as plugins from './plugins.js';
2
+ export class OidcUserInfoError extends Error {
3
+ code;
4
+ constructor(code) {
5
+ super(`OIDC userinfo ${code.replace(/_/g, ' ')}.`);
6
+ this.code = code;
7
+ this.name = 'OidcUserInfoError';
8
+ }
9
+ }
10
+ const record = (valueArg) => valueArg !== null && typeof valueArg === 'object' && !Array.isArray(valueArg);
11
+ const exactString = (valueArg, maximumArg = 512) => typeof valueArg === 'string' && valueArg.length > 0 && valueArg.length <= maximumArg
12
+ && valueArg.trim() === valueArg && !/[\u0000-\u001f\u007f]/.test(valueArg);
13
+ const strings = (valueArg) => Array.isArray(valueArg) && valueArg.every((entryArg) => exactString(entryArg))
14
+ && new Set(valueArg).size === valueArg.length;
15
+ /** Fetches display claims using a server-held token; results are never authorization grants. */
16
+ export class OidcUserInfoClient {
17
+ #endpoint;
18
+ #timeoutMs;
19
+ #maxResponseBytes;
20
+ constructor(optionsArg) {
21
+ if (!optionsArg || !exactString(optionsArg.issuer, 2048))
22
+ throw new OidcUserInfoError('invalid_request');
23
+ let issuer;
24
+ try {
25
+ issuer = new URL(optionsArg.issuer);
26
+ }
27
+ catch {
28
+ throw new OidcUserInfoError('invalid_request');
29
+ }
30
+ const canonicalIssuer = issuer.origin + (issuer.pathname === '/' ? '' : issuer.pathname);
31
+ if (issuer.protocol !== 'https:' || issuer.username || issuer.password || issuer.search || issuer.hash
32
+ || issuer.pathname.includes('//') || issuer.pathname.endsWith('/') && issuer.pathname !== '/'
33
+ || canonicalIssuer !== optionsArg.issuer)
34
+ throw new OidcUserInfoError('invalid_request');
35
+ this.#timeoutMs = optionsArg.timeoutMs ?? 5000;
36
+ this.#maxResponseBytes = optionsArg.maxResponseBytes ?? 65536;
37
+ if (!Number.isSafeInteger(this.#timeoutMs) || this.#timeoutMs < 1 || this.#timeoutMs > 30000
38
+ || !Number.isSafeInteger(this.#maxResponseBytes) || this.#maxResponseBytes < 1 || this.#maxResponseBytes > 1048576) {
39
+ throw new OidcUserInfoError('invalid_request');
40
+ }
41
+ this.#endpoint = `${canonicalIssuer}/oauth/userinfo`;
42
+ }
43
+ async getUserInfo(requestArg) {
44
+ if (!requestArg || !exactString(requestArg.subject) || !exactString(requestArg.token, 16384)
45
+ || !/^[A-Za-z0-9\-._~+/]+=*$/.test(requestArg.token))
46
+ throw new OidcUserInfoError('invalid_request');
47
+ // Snapshot the principal and token before any asynchronous work.
48
+ const { token, subject } = requestArg;
49
+ const controller = new AbortController();
50
+ let timer;
51
+ const deadline = new Promise((_resolveArg, rejectArg) => {
52
+ timer = setTimeout(() => {
53
+ controller.abort();
54
+ rejectArg(new OidcUserInfoError('unavailable'));
55
+ }, this.#timeoutMs);
56
+ });
57
+ let reader;
58
+ try {
59
+ const response = await Promise.race([fetch(this.#endpoint, {
60
+ method: 'GET', redirect: 'error', credentials: 'omit', cache: 'no-store', signal: controller.signal,
61
+ headers: { authorization: `Bearer ${token}`, accept: 'application/json' },
62
+ }), deadline]);
63
+ if (response.status === 401 || response.status === 403)
64
+ throw new OidcUserInfoError('unauthenticated');
65
+ if (response.status !== 200)
66
+ throw new OidcUserInfoError('unavailable');
67
+ if (response.headers.get('content-type')?.split(';')[0].trim().toLowerCase() !== 'application/json'
68
+ || !response.headers.get('cache-control')?.toLowerCase().split(',').map((partArg) => partArg.trim()).includes('no-store')
69
+ || !response.body)
70
+ throw new OidcUserInfoError('invalid_response');
71
+ const contentLength = response.headers.get('content-length');
72
+ if (contentLength !== null && (!/^\d+$/.test(contentLength) || Number(contentLength) > this.#maxResponseBytes)) {
73
+ throw new OidcUserInfoError('invalid_response');
74
+ }
75
+ reader = response.body.getReader();
76
+ const chunks = [];
77
+ let size = 0;
78
+ while (true) {
79
+ const part = await Promise.race([reader.read(), deadline]);
80
+ if (part.done)
81
+ break;
82
+ size += part.value.byteLength;
83
+ if (size > this.#maxResponseBytes)
84
+ throw new OidcUserInfoError('invalid_response');
85
+ chunks.push(part.value);
86
+ }
87
+ let value;
88
+ try {
89
+ value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks)));
90
+ }
91
+ catch {
92
+ throw new OidcUserInfoError('invalid_response');
93
+ }
94
+ return this.validateResponse(value, subject);
95
+ }
96
+ catch (errorArg) {
97
+ if (errorArg instanceof OidcUserInfoError)
98
+ throw errorArg;
99
+ // Transport errors can contain credentials, URLs or response bodies.
100
+ throw new OidcUserInfoError('unavailable');
101
+ }
102
+ finally {
103
+ clearTimeout(timer);
104
+ controller.abort();
105
+ if (reader)
106
+ void reader.cancel().catch(() => undefined);
107
+ }
108
+ }
109
+ validateResponse(valueArg, subjectArg) {
110
+ const invalid = () => new OidcUserInfoError('invalid_response');
111
+ if (!record(valueArg) || valueArg.sub !== subjectArg)
112
+ throw invalid();
113
+ const result = { sub: subjectArg };
114
+ for (const key of ['name', 'preferred_username', 'picture', 'email']) {
115
+ if (!Object.hasOwn(valueArg, key))
116
+ continue;
117
+ const value = valueArg[key];
118
+ if (typeof value !== 'string' || value.length > 4096)
119
+ throw invalid();
120
+ result[key] = value;
121
+ }
122
+ if (Object.hasOwn(valueArg, 'email_verified')) {
123
+ if (typeof valueArg.email_verified !== 'boolean')
124
+ throw invalid();
125
+ result.email_verified = valueArg.email_verified;
126
+ }
127
+ for (const key of ['roles', 'app_roles', 'app_permissions', 'app_scopes']) {
128
+ if (!Object.hasOwn(valueArg, key))
129
+ continue;
130
+ const value = valueArg[key];
131
+ if (!strings(value))
132
+ throw invalid();
133
+ result[key] = [...value];
134
+ }
135
+ if (Object.hasOwn(valueArg, 'organizations')) {
136
+ if (!Array.isArray(valueArg.organizations))
137
+ throw invalid();
138
+ const seen = new Set();
139
+ result.organizations = valueArg.organizations.map((organizationArg) => {
140
+ if (!record(organizationArg) || !exactString(organizationArg.id)
141
+ || typeof organizationArg.name !== 'string' || organizationArg.name.length > 4096
142
+ || !exactString(organizationArg.slug) || !strings(organizationArg.roles)
143
+ || seen.has(organizationArg.id)
144
+ || Object.keys(organizationArg).some((keyArg) => !['id', 'name', 'slug', 'roles'].includes(keyArg)))
145
+ throw invalid();
146
+ seen.add(organizationArg.id);
147
+ return { id: organizationArg.id, name: organizationArg.name, slug: organizationArg.slug, roles: [...organizationArg.roles] };
148
+ });
149
+ }
150
+ // OIDC allows additional claims; only the documented, validated fields leave the SDK.
151
+ return result;
152
+ }
153
+ }
154
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5vaWRjLXVzZXJpbmZvLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX3NlcnZlci9jbGFzc2VzLm9pZGMtdXNlcmluZm8tY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBY3hDLE1BQU0sT0FBTyxpQkFBa0IsU0FBUSxLQUFLO0lBQ2Q7SUFBNUIsWUFBNEIsSUFBZ0Y7UUFDMUcsS0FBSyxDQUFDLGlCQUFpQixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFEekIsU0FBSSxHQUFKLElBQUksQ0FBNEU7UUFFMUcsSUFBSSxDQUFDLElBQUksR0FBRyxtQkFBbUIsQ0FBQztJQUNsQyxDQUFDO0NBQ0Y7QUFFRCxNQUFNLE1BQU0sR0FBRyxDQUFDLFFBQWlCLEVBQXVDLEVBQUUsQ0FDeEUsUUFBUSxLQUFLLElBQUksSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ2hGLE1BQU0sV0FBVyxHQUFHLENBQUMsUUFBaUIsRUFBRSxVQUFVLEdBQUcsR0FBRyxFQUFzQixFQUFFLENBQzlFLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxRQUFRLENBQUMsTUFBTSxJQUFJLFVBQVU7T0FDakYsUUFBUSxDQUFDLElBQUksRUFBRSxLQUFLLFFBQVEsSUFBSSxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUM3RSxNQUFNLE9BQU8sR0FBRyxDQUFDLFFBQWlCLEVBQXdCLEVBQUUsQ0FDMUQsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUM7T0FDM0UsSUFBSSxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsSUFBSSxLQUFLLFFBQVEsQ0FBQyxNQUFNLENBQUM7QUFFaEQsZ0dBQWdHO0FBQ2hHLE1BQU0sT0FBTyxrQkFBa0I7SUFDcEIsU0FBUyxDQUFTO0lBQ2xCLFVBQVUsQ0FBUztJQUNuQixpQkFBaUIsQ0FBUztJQUVuQyxZQUFZLFVBQXNDO1FBQ2hELElBQUksQ0FBQyxVQUFVLElBQUksQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUM7WUFBRSxNQUFNLElBQUksaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUN6RyxJQUFJLE1BQVcsQ0FBQztRQUNoQixJQUFJLENBQUM7WUFBQyxNQUFNLEdBQUcsSUFBSSxHQUFHLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUFDLE1BQU0sSUFBSSxpQkFBaUIsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQUMsQ0FBQztRQUN0RyxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsTUFBTSxDQUFDLFFBQVEsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3pGLElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxJQUFJLE1BQU0sQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLElBQUk7ZUFDakcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxHQUFHO2VBQzFGLGVBQWUsS0FBSyxVQUFVLENBQUMsTUFBTTtZQUFFLE1BQU0sSUFBSSxpQkFBaUIsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQzNGLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUM7UUFDL0MsSUFBSSxDQUFDLGlCQUFpQixHQUFHLFVBQVUsQ0FBQyxnQkFBZ0IsSUFBSSxLQUFLLENBQUM7UUFDOUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSztlQUN2RixDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksSUFBSSxDQUFDLGlCQUFpQixHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsaUJBQWlCLEdBQUcsT0FBTyxFQUFFLENBQUM7WUFDckgsTUFBTSxJQUFJLGlCQUFpQixDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDakQsQ0FBQztRQUNELElBQUksQ0FBQyxTQUFTLEdBQUcsR0FBRyxlQUFlLGlCQUFpQixDQUFDO0lBQ3ZELENBQUM7SUFFTSxLQUFLLENBQUMsV0FBVyxDQUFDLFVBQXNDO1FBQzdELElBQUksQ0FBQyxVQUFVLElBQUksQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDO2VBQ3ZGLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUM7WUFBRSxNQUFNLElBQUksaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUN2RyxpRUFBaUU7UUFDakUsTUFBTSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsR0FBRyxVQUFVLENBQUM7UUFDdEMsTUFBTSxVQUFVLEdBQUcsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUN6QyxJQUFJLEtBQW9DLENBQUM7UUFDekMsTUFBTSxRQUFRLEdBQUcsSUFBSSxPQUFPLENBQVEsQ0FBQyxXQUFXLEVBQUUsU0FBUyxFQUFFLEVBQUU7WUFDN0QsS0FBSyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUU7Z0JBQ3RCLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDbkIsU0FBUyxDQUFDLElBQUksaUJBQWlCLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztZQUNsRCxDQUFDLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3RCLENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxNQUEyRCxDQUFDO1FBQ2hFLElBQUksQ0FBQztZQUNILE1BQU0sUUFBUSxHQUFHLE1BQU0sT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFO29CQUN6RCxNQUFNLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxVQUFVLENBQUMsTUFBTTtvQkFDbkcsT0FBTyxFQUFFLEVBQUUsYUFBYSxFQUFFLFVBQVUsS0FBSyxFQUFFLEVBQUUsTUFBTSxFQUFFLGtCQUFrQixFQUFFO2lCQUMxRSxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztZQUNmLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHO2dCQUFFLE1BQU0sSUFBSSxpQkFBaUIsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQ3ZHLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHO2dCQUFFLE1BQU0sSUFBSSxpQkFBaUIsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUN4RSxJQUFJLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsS0FBSyxrQkFBa0I7bUJBQzlGLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLEVBQUUsV0FBVyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQzttQkFDdEgsQ0FBQyxRQUFRLENBQUMsSUFBSTtnQkFBRSxNQUFNLElBQUksaUJBQWlCLENBQUMsa0JBQWtCLENBQUMsQ0FBQztZQUNyRSxNQUFNLGFBQWEsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1lBQzdELElBQUksYUFBYSxLQUFLLElBQUksSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxNQUFNLENBQUMsYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEVBQUUsQ0FBQztnQkFDL0csTUFBTSxJQUFJLGlCQUFpQixDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFDbEQsQ0FBQztZQUNELE1BQU0sR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25DLE1BQU0sTUFBTSxHQUFpQixFQUFFLENBQUM7WUFDaEMsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO1lBQ2IsT0FBTyxJQUFJLEVBQUUsQ0FBQztnQkFDWixNQUFNLElBQUksR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztnQkFDM0QsSUFBSSxJQUFJLENBQUMsSUFBSTtvQkFBRSxNQUFNO2dCQUNyQixJQUFJLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUM7Z0JBQzlCLElBQUksSUFBSSxHQUFHLElBQUksQ0FBQyxpQkFBaUI7b0JBQUUsTUFBTSxJQUFJLGlCQUFpQixDQUFDLGtCQUFrQixDQUFDLENBQUM7Z0JBQ25GLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzFCLENBQUM7WUFDRCxJQUFJLEtBQWMsQ0FBQztZQUNuQixJQUFJLENBQUM7Z0JBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxXQUFXLENBQUMsT0FBTyxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsQ0FBQztZQUNwRyxNQUFNLENBQUM7Z0JBQUMsTUFBTSxJQUFJLGlCQUFpQixDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFBQyxDQUFDO1lBQzFELE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztRQUMvQyxDQUFDO1FBQUMsT0FBTyxRQUFRLEVBQUUsQ0FBQztZQUNsQixJQUFJLFFBQVEsWUFBWSxpQkFBaUI7Z0JBQUUsTUFBTSxRQUFRLENBQUM7WUFDMUQscUVBQXFFO1lBQ3JFLE1BQU0sSUFBSSxpQkFBaUIsQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUM3QyxDQUFDO2dCQUFTLENBQUM7WUFDVCxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDcEIsVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ25CLElBQUksTUFBTTtnQkFBRSxLQUFLLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDMUQsQ0FBQztJQUNILENBQUM7SUFFTyxnQkFBZ0IsQ0FBQyxRQUFpQixFQUFFLFVBQWtCO1FBQzVELE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksaUJBQWlCLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUNoRSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLFFBQVEsQ0FBQyxHQUFHLEtBQUssVUFBVTtZQUFFLE1BQU0sT0FBTyxFQUFFLENBQUM7UUFDdEUsTUFBTSxNQUFNLEdBQWlELEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxDQUFDO1FBQ2pGLEtBQUssTUFBTSxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsb0JBQW9CLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBVSxFQUFFLENBQUM7WUFDOUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQztnQkFBRSxTQUFTO1lBQzVDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM1QixJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLElBQUk7Z0JBQUUsTUFBTSxPQUFPLEVBQUUsQ0FBQztZQUN0RSxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDO1FBQ3RCLENBQUM7UUFDRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLGdCQUFnQixDQUFDLEVBQUUsQ0FBQztZQUM5QyxJQUFJLE9BQU8sUUFBUSxDQUFDLGNBQWMsS0FBSyxTQUFTO2dCQUFFLE1BQU0sT0FBTyxFQUFFLENBQUM7WUFDbEUsTUFBTSxDQUFDLGNBQWMsR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDO1FBQ2xELENBQUM7UUFDRCxLQUFLLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxpQkFBaUIsRUFBRSxZQUFZLENBQVUsRUFBRSxDQUFDO1lBQ25GLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUM7Z0JBQUUsU0FBUztZQUM1QyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDNUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7Z0JBQUUsTUFBTSxPQUFPLEVBQUUsQ0FBQztZQUNyQyxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDO1FBQzNCLENBQUM7UUFDRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLGVBQWUsQ0FBQyxFQUFFLENBQUM7WUFDN0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQztnQkFBRSxNQUFNLE9BQU8sRUFBRSxDQUFDO1lBQzVELE1BQU0sSUFBSSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7WUFDL0IsTUFBTSxDQUFDLGFBQWEsR0FBRyxRQUFRLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLGVBQXdCLEVBQUUsRUFBRTtnQkFDN0UsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO3VCQUMzRCxPQUFPLGVBQWUsQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUk7dUJBQzlFLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDO3VCQUNyRSxJQUFJLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7dUJBQzVCLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUFFLE1BQU0sT0FBTyxFQUFFLENBQUM7Z0JBQ3ZILElBQUksQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUM3QixPQUFPLEVBQUUsRUFBRSxFQUFFLGVBQWUsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLGVBQWUsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLGVBQWUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsR0FBRyxlQUFlLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMvSCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxzRkFBc0Y7UUFDdEYsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztDQUNGIn0=
@@ -4,4 +4,5 @@ export * from './classes.account-doc.js';
4
4
  export * from './classes.account-store.js';
5
5
  export * from './classes.idp-global-server-client.js';
6
6
  export * from './classes.oidc-introspection-client.js';
7
+ export * from './classes.oidc-userinfo-client.js';
7
8
  export * from './classes.password-hasher.js';
@@ -4,5 +4,6 @@ export * from './classes.account-doc.js';
4
4
  export * from './classes.account-store.js';
5
5
  export * from './classes.idp-global-server-client.js';
6
6
  export * from './classes.oidc-introspection-client.js';
7
+ export * from './classes.oidc-userinfo-client.js';
7
8
  export * from './classes.password-hasher.js';
8
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19zZXJ2ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLG1DQUFtQyxDQUFDO0FBQ2xELGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLHVDQUF1QyxDQUFDO0FBQ3RELGNBQWMsd0NBQXdDLENBQUM7QUFDdkQsY0FBYyw4QkFBOEIsQ0FBQyJ9
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19zZXJ2ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLG1DQUFtQyxDQUFDO0FBQ2xELGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLHVDQUF1QyxDQUFDO0FBQ3RELGNBQWMsd0NBQXdDLENBQUM7QUFDdkQsY0FBYyxtQ0FBbUMsQ0FBQztBQUNsRCxjQUFjLDhCQUE4QixDQUFDIn0=
@@ -5,6 +5,6 @@ export { idpInterfaces };
5
5
  import * as typedrequest from '@api.global/typedrequest';
6
6
  import * as typedsocket from '@api.global/typedsocket';
7
7
  export { typedrequest, typedsocket };
8
- import * as smartdata from '@push.rocks/smartdata';
8
+ import * as nosqldb from '@lossless.org/client/nosqldb';
9
9
  import * as smartpromise from '@push.rocks/smartpromise';
10
- export { smartdata, smartpromise };
10
+ export { nosqldb, smartpromise };
@@ -5,7 +5,7 @@ export { idpInterfaces };
5
5
  import * as typedrequest from '@api.global/typedrequest';
6
6
  import * as typedsocket from '@api.global/typedsocket';
7
7
  export { typedrequest, typedsocket };
8
- import * as smartdata from '@push.rocks/smartdata';
8
+ import * as nosqldb from '@lossless.org/client/nosqldb';
9
9
  import * as smartpromise from '@push.rocks/smartpromise';
10
- export { smartdata, smartpromise };
11
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX3NlcnZlci9wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBRWpDLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQztBQUVsQixPQUFPLEtBQUssYUFBYSxNQUFNLHdCQUF3QixDQUFDO0FBRXhELE9BQU8sRUFBRSxhQUFhLEVBQUUsQ0FBQztBQUV6QixPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkQsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUVyQyxPQUFPLEtBQUssU0FBUyxNQUFNLHVCQUF1QixDQUFDO0FBQ25ELE9BQU8sS0FBSyxZQUFZLE1BQU0sMEJBQTBCLENBQUM7QUFFekQsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsQ0FBQyJ9
10
+ export { nosqldb, smartpromise };
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX3NlcnZlci9wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBRWpDLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQztBQUVsQixPQUFPLEtBQUssYUFBYSxNQUFNLHdCQUF3QixDQUFDO0FBRXhELE9BQU8sRUFBRSxhQUFhLEVBQUUsQ0FBQztBQUV6QixPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkQsT0FBTyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUVyQyxPQUFPLEtBQUssT0FBTyxNQUFNLDhCQUE4QixDQUFDO0FBQ3hELE9BQU8sS0FBSyxZQUFZLE1BQU0sMEJBQTBCLENBQUM7QUFFekQsT0FBTyxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsQ0FBQyJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idp.global/sdk",
3
- "version": "17.0.0",
3
+ "version": "18.0.0",
4
4
  "private": false,
5
5
  "description": "Reusable browser and server SDK for idp.global authentication.",
6
6
  "type": "module",
@@ -18,7 +18,6 @@
18
18
  "@api.global/typedrequest-interfaces": "^7.1.0",
19
19
  "@api.global/typedsocket": "^8.1.0",
20
20
  "@idp.global/interfaces": "^29.1.0",
21
- "@push.rocks/smartdata": "^11.7.0",
22
21
  "@push.rocks/smartjson": "^6.0.1",
23
22
  "@push.rocks/smartpromise": "^4.2.4",
24
23
  "@push.rocks/smartrx": "^3.0.12",
@@ -28,14 +27,18 @@
28
27
  "@push.rocks/webjwt": "^1.0.10",
29
28
  "@push.rocks/webstore": "^2.1.0"
30
29
  },
30
+ "peerDependencies": {
31
+ "@lossless.org/client": ">=1.0.0 <2.0.0"
32
+ },
31
33
  "devDependencies": {
32
34
  "@api.global/typedserver": "^11.4.0",
33
- "@git.zone/tsbuild": "^4.4.2",
35
+ "@git.zone/tsbuild": "^4.5.0",
34
36
  "@git.zone/tsdoc": "^2.2.0",
35
37
  "@git.zone/tsrun": "^2.0.6",
36
- "@git.zone/tstest": "^5.0.0",
37
- "@push.rocks/smartdb": "^7.0.1",
38
- "@types/node": "26.4.1"
38
+ "@git.zone/tstest": "^6.1.1",
39
+ "@lossless.org/client": "^1.0.0",
40
+ "@lossless.org/nosqldb": "10.2.0",
41
+ "@types/node": "26.5.1"
39
42
  },
40
43
  "files": [
41
44
  "ts/**/*",
@@ -60,14 +63,14 @@
60
63
  "sdk",
61
64
  "authentication",
62
65
  "oidc",
63
- "smartdata"
66
+ "nosqldb"
64
67
  ],
65
68
  "browserslist": [
66
69
  "last 1 Chrome versions"
67
70
  ],
68
71
  "scripts": {
69
72
  "test": "pnpm run build && tstest test/ --verbose --logfile --timeout 60",
70
- "build": "tsbuild tsfolders --web --allowimplicitany",
73
+ "build": "tsbuild tsfolders --web",
71
74
  "buildDocs": "tsdoc"
72
75
  }
73
76
  }
package/readme.md CHANGED
@@ -13,7 +13,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
13
13
  | Runtime | Import | What it does |
14
14
  | --- | --- | --- |
15
15
  | Browser | `@idp.global/sdk/browser` | SSO client, JWT and refresh-token storage, login redirects, logout, transfer-token exchange, and typed request shortcuts for user, organization, billing, OIDC, and admin flows. |
16
- | Server | `@idp.global/sdk/server` | Smartdata-backed account store, scrypt password hashing, local/idp.global account authentication, a server-side typed-socket client for idp.global password login, and confidential OIDC introspection. |
16
+ | Server | `@idp.global/sdk/server` | NoSQL-backed account store, scrypt password hashing, local/idp.global account authentication, a server-side typed-socket client for idp.global password login, and confidential OIDC introspection. |
17
17
 
18
18
  ## Install
19
19
 
@@ -21,6 +21,13 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
21
21
  pnpm add @idp.global/sdk
22
22
  ```
23
23
 
24
+ The server subpath additionally requires the peer dependency `@lossless.org/client`,
25
+ which provides the `SmartdataDb` the account store persists through:
26
+
27
+ ```bash
28
+ pnpm add @lossless.org/client
29
+ ```
30
+
24
31
  This is an ESM TypeScript package. Published builds expose declaration files and runtime JavaScript through package exports.
25
32
 
26
33
  Version 17 requires an IdP listener using TypedSocket 8 and TypedRequest 8
@@ -186,20 +193,24 @@ import {
186
193
 
187
194
  The server SDK is deliberately explicit: it never auto-creates accounts during authentication. Your application decides when an account exists, which auth sources it may use, and whether it is an `admin` or `user`.
188
195
 
189
- ### Smartdata Account Store
196
+ ### Account Store
190
197
 
191
- `SmartdataAccountStore` persists accounts through `@push.rocks/smartdata` and the exported `IdpSdkAccountDoc` collection.
198
+ `SmartdataAccountStore` persists accounts through `@lossless.org/client/nosqldb`
199
+ and the exported `IdpSdkAccountDoc` collection.
192
200
 
193
- The server SDK requires SmartData 11.7 or newer within major 11. Applications
194
- that pass a `SmartdataDb` must use the same SmartData major. Existing SDK account
195
- documents and their `id_1` identity index retain their schema; this dependency
196
- migration does not transform stored accounts.
201
+ `@lossless.org/client` is a required peer dependency within major 1. The
202
+ `SmartdataDb` you pass must come from that package: the account document is
203
+ decorated by the very same module, so a `SmartdataDb` from any other package is
204
+ rejected at compile time and cannot resolve the model at runtime. Existing SDK
205
+ account documents, their `id_1` identity index and their `scrypt:v1` password
206
+ hashes retain their exact stored shape; this dependency migration does not
207
+ transform stored accounts.
197
208
 
198
209
  ```ts
199
- import * as smartdata from '@push.rocks/smartdata';
210
+ import * as nosqldb from '@lossless.org/client/nosqldb';
200
211
  import { SmartdataAccountStore } from '@idp.global/sdk/server';
201
212
 
202
- const smartdataDb = new smartdata.SmartdataDb({
213
+ const smartdataDb = new nosqldb.SmartdataDb({
203
214
  mongoDbUrl: process.env.MONGODB_URL!,
204
215
  mongoDbName: 'my-app',
205
216
  });
@@ -338,20 +349,57 @@ existing login and principal binding and make a fresh observation for each
338
349
  operation requiring live authority. The response contains no identity profile
339
350
  or email-based organization inference.
340
351
 
352
+ ### Server-held OIDC UserInfo
353
+
354
+ Use `OidcUserInfoClient` to obtain current profile and organization picker data
355
+ with an access token held by your application's server session:
356
+
357
+ ```typescript
358
+ import { OidcUserInfoClient } from '@idp.global/sdk/server';
359
+
360
+ const userInfoClient = new OidcUserInfoClient({ issuer: 'https://idp.global' });
361
+ const claims = await userInfoClient.getUserInfo({
362
+ token: serverSession.accessToken,
363
+ subject: serverSession.idpSubject,
364
+ });
365
+ const ownerOrganizations = claims.organizations?.filter((organization) =>
366
+ organization.roles.includes('owner')) ?? [];
367
+ ```
368
+
369
+ The expected subject must come from the verified OIDC login. Keep the token
370
+ server-side; the SDK sends it only in the bearer header to the issuer's
371
+ `/oauth/userinfo` endpoint, rejects redirects, and validates the returned subject
372
+ and documented claims. Unknown top-level OIDC extension claims are omitted.
373
+ The client retains no access token or claim cache. Calls have a five-second
374
+ deadline, including body reads, and a 64 KiB response limit. Options allow a
375
+ deadline up to 30 seconds and a response limit up to 1 MiB.
376
+
377
+ Organization claims are display data within the token's original organization
378
+ grant. Newly granted organizations require a new OIDC login; removed memberships
379
+ or app connections disappear from subsequent responses. Authorize each protected
380
+ operation separately with fresh `OidcIntrospectionClient` introspection. UserInfo
381
+ does not turn a picker selection or an observed role into an authorization grant.
382
+
383
+ `OidcUserInfoError.code` is `invalid_request`, `invalid_response`,
384
+ `unauthenticated`, or `unavailable`. Provider 401/403 responses indicate that the
385
+ server-held token is no longer accepted. Errors omit token and provider content.
386
+
341
387
  ### Server API Surface
342
388
 
343
389
  | API | Description |
344
390
  | --- | --- |
345
- | `SmartdataAccountStore` | Smartdata-backed account persistence and local password verification. |
391
+ | `SmartdataAccountStore` | NoSQL-backed account persistence and local password verification. |
346
392
  | `AccountAuthService` | Existing-account authentication orchestration for `local`, `idp.global`, and `auto`. |
347
393
  | `IdpGlobalServerClient` | Typed-socket client for idp.global password login, JWT refresh, `whoIs` lookup, backend JWT validation fetches, and JWT key/blocklist pushes. |
348
394
  | `OidcIntrospectionClient` | Confidential server client for an exact live organization authority observation. |
349
395
  | `OidcIntrospectionError` | Sanitized introspection failure with a stable error code. |
396
+ | `OidcUserInfoClient` | Subject-bound profile and organization display claims using a server-held OIDC token. |
397
+ | `OidcUserInfoError` | Sanitized UserInfo failure with a stable error code. |
350
398
  | `IdpMfaRequiredError` | Password-login error carrying the MFA challenge token and available factor methods. |
351
399
  | `defaultIdpGlobalBaseUrl` | Default hosted server origin: `https://app.idp.global`. |
352
400
  | `PasswordHasher` | Static `hashPassword()` and `verifyPassword()` helpers using `scrypt:v1`. |
353
- | `IdpSdkAccountDoc` | Smartdata document class backing persisted SDK accounts. |
354
- | `setAccountDocSmartdataDb()` | Configure the active Smartdata DB for `IdpSdkAccountDoc`. Usually handled by `SmartdataAccountStore`. |
401
+ | `IdpSdkAccountDoc` | `@lossless.org/client/nosqldb` document class backing persisted SDK accounts. |
402
+ | `setAccountDocSmartdataDb()` | Configure the active `SmartdataDb` for `IdpSdkAccountDoc`. Usually handled by `SmartdataAccountStore`. |
355
403
 
356
404
  ### Types
357
405
 
@@ -361,6 +409,8 @@ The server export includes these TypeScript types:
361
409
  | --- | --- |
362
410
  | `IOidcIntrospectionClientOptions` | Exact HTTPS issuer, confidential client credentials, and optional deadline/response limits. |
363
411
  | `IOidcIntrospectionClientRequest` | Server-held access token, exact subject, and canonical organization ID. |
412
+ | `IOidcUserInfoClientOptions` | Exact HTTPS issuer and optional deadline/response limits. |
413
+ | `IOidcUserInfoClientRequest` | Server-held access token and the subject established by verified OIDC login. |
364
414
  | `TIdpAccountAuthSource` | `'local' | 'idp.global'` |
365
415
  | `TIdpAccountRole` | `'admin' | 'user'` |
366
416
  | `TIdpAccountStatus` | `'active' | 'disabled'` |
@@ -380,7 +430,7 @@ import { IdpClient } from '@idp.global/sdk/browser';
380
430
  import { AccountAuthService } from '@idp.global/sdk/server';
381
431
  ```
382
432
 
383
- The SDK uses typed sockets and typed requests from `@api.global/*`, shared idp.global request contracts from `@idp.global/interfaces`, and focused Push Rocks utilities for URL handling, JSON/base64 encoding, observables, JWT decoding, browser storage, smartdata persistence, and promise coordination.
433
+ The SDK uses typed sockets and typed requests from `@api.global/*`, shared idp.global request contracts from `@idp.global/interfaces`, NoSQL persistence from `@lossless.org/client/nosqldb`, and focused Push Rocks utilities for URL handling, JSON/base64 encoding, observables, JWT decoding, browser storage, and promise coordination.
384
434
 
385
435
  ## Testing
386
436
 
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@idp.global/sdk',
6
- version: '17.0.0',
6
+ version: '18.0.0',
7
7
  description: 'Reusable browser and server SDK for idp.global authentication.'
8
8
  }
@@ -1,9 +1,9 @@
1
1
  import * as plugins from './plugins.js';
2
2
  import type { IIdpSdkAccount, TIdpAccountAuthSource, TIdpAccountRole, TIdpAccountStatus } from './interfaces.js';
3
3
 
4
- let activeSmartdataDb: plugins.smartdata.SmartdataDb | null = null;
4
+ let activeSmartdataDb: plugins.nosqldb.SmartdataDb | null = null;
5
5
 
6
- export const setAccountDocSmartdataDb = (smartdataDbArg: plugins.smartdata.SmartdataDb) => {
6
+ export const setAccountDocSmartdataDb = (smartdataDbArg: plugins.nosqldb.SmartdataDb) => {
7
7
  activeSmartdataDb = smartdataDbArg;
8
8
  };
9
9
 
@@ -14,43 +14,43 @@ const getDb = () => {
14
14
  return activeSmartdataDb;
15
15
  };
16
16
 
17
- @plugins.smartdata.Collection(() => getDb())
18
- export class IdpSdkAccountDoc extends plugins.smartdata.SmartDataDbDoc<IdpSdkAccountDoc, IdpSdkAccountDoc> {
19
- @plugins.smartdata.unI()
20
- @plugins.smartdata.svDb()
17
+ @plugins.nosqldb.Collection(() => getDb())
18
+ export class IdpSdkAccountDoc extends plugins.nosqldb.SmartDataDbDoc<IdpSdkAccountDoc, IdpSdkAccountDoc> {
19
+ @plugins.nosqldb.unI()
20
+ @plugins.nosqldb.svDb()
21
21
  public id!: string;
22
22
 
23
- @plugins.smartdata.svDb()
23
+ @plugins.nosqldb.svDb()
24
24
  public email!: string;
25
25
 
26
- @plugins.smartdata.svDb()
26
+ @plugins.nosqldb.svDb()
27
27
  public emailNormalized!: string;
28
28
 
29
- @plugins.smartdata.svDb()
29
+ @plugins.nosqldb.svDb()
30
30
  public name: string = '';
31
31
 
32
- @plugins.smartdata.svDb()
32
+ @plugins.nosqldb.svDb()
33
33
  public role!: TIdpAccountRole;
34
34
 
35
- @plugins.smartdata.svDb()
35
+ @plugins.nosqldb.svDb()
36
36
  public status!: TIdpAccountStatus;
37
37
 
38
- @plugins.smartdata.svDb()
38
+ @plugins.nosqldb.svDb()
39
39
  public authSources!: TIdpAccountAuthSource[];
40
40
 
41
- @plugins.smartdata.svDb()
41
+ @plugins.nosqldb.svDb()
42
42
  public passwordHash?: string;
43
43
 
44
- @plugins.smartdata.svDb()
44
+ @plugins.nosqldb.svDb()
45
45
  public idpSubject?: string;
46
46
 
47
- @plugins.smartdata.svDb()
47
+ @plugins.nosqldb.svDb()
48
48
  public createdAt!: number;
49
49
 
50
- @plugins.smartdata.svDb()
50
+ @plugins.nosqldb.svDb()
51
51
  public updatedAt!: number;
52
52
 
53
- @plugins.smartdata.svDb()
53
+ @plugins.nosqldb.svDb()
54
54
  public lastLoginAt?: number;
55
55
 
56
56
  public toAccount(): IIdpSdkAccount {
@@ -4,7 +4,7 @@ import { PasswordHasher } from './classes.password-hasher.js';
4
4
  import type { ICreateIdpSdkAccountOptions, IIdpSdkAccount, TIdpAccountAuthSource } from './interfaces.js';
5
5
 
6
6
  export class SmartdataAccountStore {
7
- constructor(private optionsArg: { smartdataDb: plugins.smartdata.SmartdataDb }) {
7
+ constructor(private optionsArg: { smartdataDb: plugins.nosqldb.SmartdataDb }) {
8
8
  setAccountDocSmartdataDb(optionsArg.smartdataDb);
9
9
  }
10
10
 
@@ -0,0 +1,143 @@
1
+ import * as plugins from './plugins.js';
2
+
3
+ export interface IOidcUserInfoClientOptions {
4
+ issuer: string;
5
+ timeoutMs?: number;
6
+ maxResponseBytes?: number;
7
+ }
8
+
9
+ export interface IOidcUserInfoClientRequest {
10
+ token: string;
11
+ /** Subject already established by the application's verified OIDC login. */
12
+ subject: string;
13
+ }
14
+
15
+ export class OidcUserInfoError extends Error {
16
+ constructor(public readonly code: 'invalid_request' | 'invalid_response' | 'unauthenticated' | 'unavailable') {
17
+ super(`OIDC userinfo ${code.replace(/_/g, ' ')}.`);
18
+ this.name = 'OidcUserInfoError';
19
+ }
20
+ }
21
+
22
+ const record = (valueArg: unknown): valueArg is Record<string, unknown> =>
23
+ valueArg !== null && typeof valueArg === 'object' && !Array.isArray(valueArg);
24
+ const exactString = (valueArg: unknown, maximumArg = 512): valueArg is string =>
25
+ typeof valueArg === 'string' && valueArg.length > 0 && valueArg.length <= maximumArg
26
+ && valueArg.trim() === valueArg && !/[\u0000-\u001f\u007f]/.test(valueArg);
27
+ const strings = (valueArg: unknown): valueArg is string[] =>
28
+ Array.isArray(valueArg) && valueArg.every((entryArg) => exactString(entryArg))
29
+ && new Set(valueArg).size === valueArg.length;
30
+
31
+ /** Fetches display claims using a server-held token; results are never authorization grants. */
32
+ export class OidcUserInfoClient {
33
+ readonly #endpoint: string;
34
+ readonly #timeoutMs: number;
35
+ readonly #maxResponseBytes: number;
36
+
37
+ constructor(optionsArg: IOidcUserInfoClientOptions) {
38
+ if (!optionsArg || !exactString(optionsArg.issuer, 2048)) throw new OidcUserInfoError('invalid_request');
39
+ let issuer: URL;
40
+ try { issuer = new URL(optionsArg.issuer); } catch { throw new OidcUserInfoError('invalid_request'); }
41
+ const canonicalIssuer = issuer.origin + (issuer.pathname === '/' ? '' : issuer.pathname);
42
+ if (issuer.protocol !== 'https:' || issuer.username || issuer.password || issuer.search || issuer.hash
43
+ || issuer.pathname.includes('//') || issuer.pathname.endsWith('/') && issuer.pathname !== '/'
44
+ || canonicalIssuer !== optionsArg.issuer) throw new OidcUserInfoError('invalid_request');
45
+ this.#timeoutMs = optionsArg.timeoutMs ?? 5000;
46
+ this.#maxResponseBytes = optionsArg.maxResponseBytes ?? 65536;
47
+ if (!Number.isSafeInteger(this.#timeoutMs) || this.#timeoutMs < 1 || this.#timeoutMs > 30000
48
+ || !Number.isSafeInteger(this.#maxResponseBytes) || this.#maxResponseBytes < 1 || this.#maxResponseBytes > 1048576) {
49
+ throw new OidcUserInfoError('invalid_request');
50
+ }
51
+ this.#endpoint = `${canonicalIssuer}/oauth/userinfo`;
52
+ }
53
+
54
+ public async getUserInfo(requestArg: IOidcUserInfoClientRequest): Promise<plugins.idpInterfaces.data.IUserInfoResponse> {
55
+ if (!requestArg || !exactString(requestArg.subject) || !exactString(requestArg.token, 16384)
56
+ || !/^[A-Za-z0-9\-._~+/]+=*$/.test(requestArg.token)) throw new OidcUserInfoError('invalid_request');
57
+ // Snapshot the principal and token before any asynchronous work.
58
+ const { token, subject } = requestArg;
59
+ const controller = new AbortController();
60
+ let timer: ReturnType<typeof setTimeout>;
61
+ const deadline = new Promise<never>((_resolveArg, rejectArg) => {
62
+ timer = setTimeout(() => {
63
+ controller.abort();
64
+ rejectArg(new OidcUserInfoError('unavailable'));
65
+ }, this.#timeoutMs);
66
+ });
67
+ let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;
68
+ try {
69
+ const response = await Promise.race([fetch(this.#endpoint, {
70
+ method: 'GET', redirect: 'error', credentials: 'omit', cache: 'no-store', signal: controller.signal,
71
+ headers: { authorization: `Bearer ${token}`, accept: 'application/json' },
72
+ }), deadline]);
73
+ if (response.status === 401 || response.status === 403) throw new OidcUserInfoError('unauthenticated');
74
+ if (response.status !== 200) throw new OidcUserInfoError('unavailable');
75
+ if (response.headers.get('content-type')?.split(';')[0].trim().toLowerCase() !== 'application/json'
76
+ || !response.headers.get('cache-control')?.toLowerCase().split(',').map((partArg) => partArg.trim()).includes('no-store')
77
+ || !response.body) throw new OidcUserInfoError('invalid_response');
78
+ const contentLength = response.headers.get('content-length');
79
+ if (contentLength !== null && (!/^\d+$/.test(contentLength) || Number(contentLength) > this.#maxResponseBytes)) {
80
+ throw new OidcUserInfoError('invalid_response');
81
+ }
82
+ reader = response.body.getReader();
83
+ const chunks: Uint8Array[] = [];
84
+ let size = 0;
85
+ while (true) {
86
+ const part = await Promise.race([reader.read(), deadline]);
87
+ if (part.done) break;
88
+ size += part.value.byteLength;
89
+ if (size > this.#maxResponseBytes) throw new OidcUserInfoError('invalid_response');
90
+ chunks.push(part.value);
91
+ }
92
+ let value: unknown;
93
+ try { value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks))); }
94
+ catch { throw new OidcUserInfoError('invalid_response'); }
95
+ return this.validateResponse(value, subject);
96
+ } catch (errorArg) {
97
+ if (errorArg instanceof OidcUserInfoError) throw errorArg;
98
+ // Transport errors can contain credentials, URLs or response bodies.
99
+ throw new OidcUserInfoError('unavailable');
100
+ } finally {
101
+ clearTimeout(timer);
102
+ controller.abort();
103
+ if (reader) void reader.cancel().catch(() => undefined);
104
+ }
105
+ }
106
+
107
+ private validateResponse(valueArg: unknown, subjectArg: string): plugins.idpInterfaces.data.IUserInfoResponse {
108
+ const invalid = () => new OidcUserInfoError('invalid_response');
109
+ if (!record(valueArg) || valueArg.sub !== subjectArg) throw invalid();
110
+ const result: plugins.idpInterfaces.data.IUserInfoResponse = { sub: subjectArg };
111
+ for (const key of ['name', 'preferred_username', 'picture', 'email'] as const) {
112
+ if (!Object.hasOwn(valueArg, key)) continue;
113
+ const value = valueArg[key];
114
+ if (typeof value !== 'string' || value.length > 4096) throw invalid();
115
+ result[key] = value;
116
+ }
117
+ if (Object.hasOwn(valueArg, 'email_verified')) {
118
+ if (typeof valueArg.email_verified !== 'boolean') throw invalid();
119
+ result.email_verified = valueArg.email_verified;
120
+ }
121
+ for (const key of ['roles', 'app_roles', 'app_permissions', 'app_scopes'] as const) {
122
+ if (!Object.hasOwn(valueArg, key)) continue;
123
+ const value = valueArg[key];
124
+ if (!strings(value)) throw invalid();
125
+ result[key] = [...value];
126
+ }
127
+ if (Object.hasOwn(valueArg, 'organizations')) {
128
+ if (!Array.isArray(valueArg.organizations)) throw invalid();
129
+ const seen = new Set<string>();
130
+ result.organizations = valueArg.organizations.map((organizationArg: unknown) => {
131
+ if (!record(organizationArg) || !exactString(organizationArg.id)
132
+ || typeof organizationArg.name !== 'string' || organizationArg.name.length > 4096
133
+ || !exactString(organizationArg.slug) || !strings(organizationArg.roles)
134
+ || seen.has(organizationArg.id)
135
+ || Object.keys(organizationArg).some((keyArg) => !['id', 'name', 'slug', 'roles'].includes(keyArg))) throw invalid();
136
+ seen.add(organizationArg.id);
137
+ return { id: organizationArg.id, name: organizationArg.name, slug: organizationArg.slug, roles: [...organizationArg.roles] };
138
+ });
139
+ }
140
+ // OIDC allows additional claims; only the documented, validated fields leave the SDK.
141
+ return result;
142
+ }
143
+ }
@@ -4,4 +4,5 @@ export * from './classes.account-doc.js';
4
4
  export * from './classes.account-store.js';
5
5
  export * from './classes.idp-global-server-client.js';
6
6
  export * from './classes.oidc-introspection-client.js';
7
+ export * from './classes.oidc-userinfo-client.js';
7
8
  export * from './classes.password-hasher.js';
@@ -11,7 +11,7 @@ import * as typedsocket from '@api.global/typedsocket';
11
11
 
12
12
  export { typedrequest, typedsocket };
13
13
 
14
- import * as smartdata from '@push.rocks/smartdata';
14
+ import * as nosqldb from '@lossless.org/client/nosqldb';
15
15
  import * as smartpromise from '@push.rocks/smartpromise';
16
16
 
17
- export { smartdata, smartpromise };
17
+ export { nosqldb, smartpromise };