@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 +25 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_server/classes.account-doc.d.ts +2 -2
- package/dist_ts_server/classes.account-doc.js +15 -15
- package/dist_ts_server/classes.account-store.d.ts +1 -1
- package/dist_ts_server/classes.account-store.js +1 -1
- package/dist_ts_server/classes.oidc-userinfo-client.d.ts +22 -0
- package/dist_ts_server/classes.oidc-userinfo-client.js +154 -0
- package/dist_ts_server/index.d.ts +1 -0
- package/dist_ts_server/index.js +2 -1
- package/dist_ts_server/plugins.d.ts +2 -2
- package/dist_ts_server/plugins.js +3 -3
- package/package.json +11 -8
- package/readme.md +63 -13
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_server/classes.account-doc.ts +17 -17
- package/ts_server/classes.account-store.ts +1 -1
- package/ts_server/classes.oidc-userinfo-client.ts +143 -0
- package/ts_server/index.ts +1 -0
- package/ts_server/plugins.ts +2 -2
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: '
|
|
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.
|
|
4
|
-
export declare class IdpSdkAccountDoc extends plugins.
|
|
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.
|
|
47
|
+
let _classDecorators = [plugins.nosqldb.Collection(() => getDb())];
|
|
48
48
|
let _classDescriptor;
|
|
49
49
|
let _classExtraInitializers = [];
|
|
50
50
|
let _classThis;
|
|
51
|
-
let _classSuper = plugins.
|
|
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.
|
|
93
|
-
_email_decorators = [plugins.
|
|
94
|
-
_emailNormalized_decorators = [plugins.
|
|
95
|
-
_name_decorators = [plugins.
|
|
96
|
-
_role_decorators = [plugins.
|
|
97
|
-
_status_decorators = [plugins.
|
|
98
|
-
_authSources_decorators = [plugins.
|
|
99
|
-
_passwordHash_decorators = [plugins.
|
|
100
|
-
_idpSubject_decorators = [plugins.
|
|
101
|
-
_createdAt_decorators = [plugins.
|
|
102
|
-
_updatedAt_decorators = [plugins.
|
|
103
|
-
_lastLoginAt_decorators = [plugins.
|
|
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,
|
|
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.
|
|
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,
|
|
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5vaWRjLXVzZXJpbmZvLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX3NlcnZlci9jbGFzc2VzLm9pZGMtdXNlcmluZm8tY2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBY3hDLE1BQU0sT0FBTyxpQkFBa0IsU0FBUSxLQUFLO0lBQ2Q7SUFBNUIsWUFBNEIsSUFBZ0Y7UUFDMUcsS0FBSyxDQUFDLGlCQUFpQixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFEekIsU0FBSSxHQUFKLElBQUksQ0FBNEU7UUFFMUcsSUFBSSxDQUFDLElBQUksR0FBRyxtQkFBbUIsQ0FBQztJQUNsQyxDQUFDO0NBQ0Y7QUFFRCxNQUFNLE1BQU0sR0FBRyxDQUFDLFFBQWlCLEVBQXVDLEVBQUUsQ0FDeEUsUUFBUSxLQUFLLElBQUksSUFBSSxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ2hGLE1BQU0sV0FBVyxHQUFHLENBQUMsUUFBaUIsRUFBRSxVQUFVLEdBQUcsR0FBRyxFQUFzQixFQUFFLENBQzlFLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxRQUFRLENBQUMsTUFBTSxJQUFJLFVBQVU7T0FDakYsUUFBUSxDQUFDLElBQUksRUFBRSxLQUFLLFFBQVEsSUFBSSxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUM3RSxNQUFNLE9BQU8sR0FBRyxDQUFDLFFBQWlCLEVBQXdCLEVBQUUsQ0FDMUQsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxXQUFX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
|
|
@@ -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';
|
package/dist_ts_server/index.js
CHANGED
|
@@ -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,
|
|
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
|
|
8
|
+
import * as nosqldb from '@lossless.org/client/nosqldb';
|
|
9
9
|
import * as smartpromise from '@push.rocks/smartpromise';
|
|
10
|
-
export {
|
|
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
|
|
8
|
+
import * as nosqldb from '@lossless.org/client/nosqldb';
|
|
9
9
|
import * as smartpromise from '@push.rocks/smartpromise';
|
|
10
|
-
export {
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
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": "
|
|
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.
|
|
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": "^
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
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
|
-
"
|
|
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
|
|
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` |
|
|
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
|
-
###
|
|
196
|
+
### Account Store
|
|
190
197
|
|
|
191
|
-
`SmartdataAccountStore` persists accounts through `@
|
|
198
|
+
`SmartdataAccountStore` persists accounts through `@lossless.org/client/nosqldb`
|
|
199
|
+
and the exported `IdpSdkAccountDoc` collection.
|
|
192
200
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
|
210
|
+
import * as nosqldb from '@lossless.org/client/nosqldb';
|
|
200
211
|
import { SmartdataAccountStore } from '@idp.global/sdk/server';
|
|
201
212
|
|
|
202
|
-
const smartdataDb = new
|
|
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` |
|
|
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` |
|
|
354
|
-
| `setAccountDocSmartdataDb()` | Configure the active
|
|
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,
|
|
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
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -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.
|
|
4
|
+
let activeSmartdataDb: plugins.nosqldb.SmartdataDb | null = null;
|
|
5
5
|
|
|
6
|
-
export const setAccountDocSmartdataDb = (smartdataDbArg: plugins.
|
|
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.
|
|
18
|
-
export class IdpSdkAccountDoc extends plugins.
|
|
19
|
-
@plugins.
|
|
20
|
-
@plugins.
|
|
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.
|
|
23
|
+
@plugins.nosqldb.svDb()
|
|
24
24
|
public email!: string;
|
|
25
25
|
|
|
26
|
-
@plugins.
|
|
26
|
+
@plugins.nosqldb.svDb()
|
|
27
27
|
public emailNormalized!: string;
|
|
28
28
|
|
|
29
|
-
@plugins.
|
|
29
|
+
@plugins.nosqldb.svDb()
|
|
30
30
|
public name: string = '';
|
|
31
31
|
|
|
32
|
-
@plugins.
|
|
32
|
+
@plugins.nosqldb.svDb()
|
|
33
33
|
public role!: TIdpAccountRole;
|
|
34
34
|
|
|
35
|
-
@plugins.
|
|
35
|
+
@plugins.nosqldb.svDb()
|
|
36
36
|
public status!: TIdpAccountStatus;
|
|
37
37
|
|
|
38
|
-
@plugins.
|
|
38
|
+
@plugins.nosqldb.svDb()
|
|
39
39
|
public authSources!: TIdpAccountAuthSource[];
|
|
40
40
|
|
|
41
|
-
@plugins.
|
|
41
|
+
@plugins.nosqldb.svDb()
|
|
42
42
|
public passwordHash?: string;
|
|
43
43
|
|
|
44
|
-
@plugins.
|
|
44
|
+
@plugins.nosqldb.svDb()
|
|
45
45
|
public idpSubject?: string;
|
|
46
46
|
|
|
47
|
-
@plugins.
|
|
47
|
+
@plugins.nosqldb.svDb()
|
|
48
48
|
public createdAt!: number;
|
|
49
49
|
|
|
50
|
-
@plugins.
|
|
50
|
+
@plugins.nosqldb.svDb()
|
|
51
51
|
public updatedAt!: number;
|
|
52
52
|
|
|
53
|
-
@plugins.
|
|
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.
|
|
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
|
+
}
|
package/ts_server/index.ts
CHANGED
|
@@ -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';
|
package/ts_server/plugins.ts
CHANGED
|
@@ -11,7 +11,7 @@ import * as typedsocket from '@api.global/typedsocket';
|
|
|
11
11
|
|
|
12
12
|
export { typedrequest, typedsocket };
|
|
13
13
|
|
|
14
|
-
import * as
|
|
14
|
+
import * as nosqldb from '@lossless.org/client/nosqldb';
|
|
15
15
|
import * as smartpromise from '@push.rocks/smartpromise';
|
|
16
16
|
|
|
17
|
-
export {
|
|
17
|
+
export { nosqldb, smartpromise };
|