@idp.global/sdk 19.3.0 → 19.4.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 +40 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_browser/classes.idpclient.js +1 -1
- package/dist_ts_browser/classes.idprequests.js +1 -1
- package/dist_ts_browser/classes.relyingpartybearerclient.d.ts +276 -0
- package/dist_ts_browser/classes.relyingpartybearerclient.js +591 -0
- package/dist_ts_browser/index.d.ts +1 -0
- package/dist_ts_browser/index.js +2 -1
- package/dist_ts_browser/plugins.js +1 -1
- package/dist_ts_browser/secret-delivery.js +1 -1
- package/dist_ts_relyingparty/classes.authorityobserver.d.ts +23 -0
- package/dist_ts_relyingparty/classes.authorityobserver.js +68 -13
- package/dist_ts_relyingparty/classes.errors.d.ts +3 -1
- package/dist_ts_relyingparty/classes.errors.js +2 -1
- package/dist_ts_relyingparty/classes.relyingpartyroutes.d.ts +12 -0
- package/dist_ts_relyingparty/classes.relyingpartyroutes.js +33 -6
- package/dist_ts_relyingparty/classes.relyingpartysessions.d.ts +102 -7
- package/dist_ts_relyingparty/classes.relyingpartysessions.js +228 -29
- package/dist_ts_relyingparty/classes.rpmodels.d.ts +6 -4
- package/dist_ts_relyingparty/classes.rpmodels.js +8 -6
- package/dist_ts_relyingparty/contract.bearer.d.ts +82 -0
- package/dist_ts_relyingparty/contract.bearer.js +9 -0
- package/dist_ts_relyingparty/helpers.bearer.d.ts +3 -3
- package/dist_ts_relyingparty/helpers.bearer.js +3 -3
- package/dist_ts_relyingparty/interfaces.d.ts +34 -24
- package/package.json +2 -1
- package/readme.md +215 -19
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_browser/classes.relyingpartybearerclient.ts +821 -0
- package/ts_browser/index.ts +1 -0
- package/ts_relyingparty/classes.authorityobserver.ts +80 -12
- package/ts_relyingparty/classes.errors.ts +4 -1
- package/ts_relyingparty/classes.relyingpartyroutes.ts +38 -7
- package/ts_relyingparty/classes.relyingpartysessions.ts +298 -34
- package/ts_relyingparty/classes.rpmodels.ts +7 -4
- package/ts_relyingparty/contract.bearer.ts +99 -0
- package/ts_relyingparty/helpers.bearer.ts +8 -9
- package/ts_relyingparty/interfaces.ts +49 -26
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type IOidcProvider } from './classes.idpoidcprovider.js';
|
|
2
2
|
import type { IRelyingPartyModels } from './classes.rpmodels.js';
|
|
3
|
-
import type { IAuthorityTokenSource, IProviderToken, IRelyingPartyBearerDelivery, IRelyingPartyBearerHandoff, IRelyingPartyBearerLoginRequest, IRelyingPartyBearerLoginStart, IRelyingPartyBearerOptions, IRelyingPartyBearerReturnTargets, IRelyingPartyBearerTokens, IRelyingPartyHooks, IRelyingPartyLiveSession, IRelyingPartyLoginOptions, IRelyingPartyLoginStart, IRelyingPartySession, IRelyingPartySessionOpening, IResolvedRelyingPartySession, TRelyingPartyPrincipals, TRelyingPartySessionEndReason } from './interfaces.js';
|
|
3
|
+
import type { IAuthorityTokenSource, IProviderToken, IRelyingPartyBearerDelivery, IRelyingPartyBearerHandoff, IRelyingPartyBearerLoginRequest, IRelyingPartyBearerLoginStart, IRelyingPartyBearerOptions, IRelyingPartyBearerReturnTargets, IRelyingPartyBearerTokens, IRelyingPartyHooks, IRelyingPartyLiveSession, IRelyingPartyLoginOptions, IRelyingPartyLoginStart, IRelyingPartySession, IRelyingPartySessionOpening, IRelyingPartySessionsPage, IRelyingPartySessionsPageOptions, IResolvedRelyingPartySession, TRelyingPartyPrincipals, TRelyingPartySessionEndReason } from './interfaces.js';
|
|
4
4
|
export declare const RELYING_PARTY_DEFAULT_SESSION_MAX_AGE_SECONDS: number;
|
|
5
5
|
export declare const RELYING_PARTY_DEFAULT_LOGIN_PATH_PREFIX = "/auth/";
|
|
6
6
|
/** The label the CSRF HMAC starts with unless the application names its own. */
|
|
@@ -9,6 +9,10 @@ export declare const RELYING_PARTY_DEFAULT_CSRF_LABEL: string;
|
|
|
9
9
|
export declare const LOGIN_ATTEMPT_MAX_AGE_SECONDS: number;
|
|
10
10
|
/** The longest intent a login carries (`IRelyingPartyLoginOptions.intent`), in characters. */
|
|
11
11
|
export declare const RELYING_PARTY_MAX_INTENT_LENGTH = 4096;
|
|
12
|
+
/** How many sessions one page of `sessionsOfPrincipal` holds unless its `limit` says otherwise. */
|
|
13
|
+
export declare const RELYING_PARTY_DEFAULT_SESSIONS_PAGE_LIMIT = 100;
|
|
14
|
+
/** The largest `limit` of `sessionsOfPrincipal`; the store reads no larger page. */
|
|
15
|
+
export declare const RELYING_PARTY_MAX_SESSIONS_PAGE_LIMIT = 1000;
|
|
12
16
|
/** How long a bearer hand-off code can be claimed, at most; never past its session. */
|
|
13
17
|
export declare const BEARER_HANDOFF_MAX_AGE_SECONDS = 60;
|
|
14
18
|
/** How long a bearer access token lives unless `bearer.accessTokenMaxAgeSeconds` says otherwise. */
|
|
@@ -40,6 +44,12 @@ export interface IRelyingPartySessionsOptions<TPrincipal extends object | undefi
|
|
|
40
44
|
sessionEncryptionKey: Buffer;
|
|
41
45
|
/** 32 bytes; the CSRF HMAC key */
|
|
42
46
|
csrfKey: Buffer;
|
|
47
|
+
/**
|
|
48
|
+
* `true` (the default): cookie sessions with a session-bound CSRF token,
|
|
49
|
+
* beside bearer hand-off mode when `bearer` is given. Bearer hand-off alone,
|
|
50
|
+
* without any cookie, is `IRelyingPartyBearerOnlySessionsOptions`.
|
|
51
|
+
*/
|
|
52
|
+
cookieSessions?: true;
|
|
43
53
|
/** the label the CSRF HMAC starts with; an application with live sessions keeps its own */
|
|
44
54
|
csrfLabel?: string;
|
|
45
55
|
sessionMaxAgeSeconds?: number;
|
|
@@ -63,15 +73,42 @@ export interface IRelyingPartySessionsOptions<TPrincipal extends object | undefi
|
|
|
63
73
|
/** the clock every comparison reads; tests step it instead of sleeping */
|
|
64
74
|
now?: () => number;
|
|
65
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Bearer-only mode (`cookieSessions: false`): the application's own clients
|
|
78
|
+
* sign in through bearer hand-off and nothing else. The relying party never
|
|
79
|
+
* reads or sets a cookie — not even the clearing intent cookie of a callback
|
|
80
|
+
* that is no bearer login — so it has no CSRF token and takes no CSRF key:
|
|
81
|
+
* `csrfKey`, `csrfLabel` and `cookieNames` are refused, not ignored. The
|
|
82
|
+
* cookie steps (`openSession`, `startLogin`, `completeLogin`, `abandonLogin`,
|
|
83
|
+
* `finalizeLogin`, `clearSessionCookie`, `clearIntentCookie`) throw
|
|
84
|
+
* `RelyingPartyError('login_method_unavailable')` and `resolveCookieSession`
|
|
85
|
+
* answers `null`.
|
|
86
|
+
*/
|
|
87
|
+
export interface IRelyingPartyBearerOnlySessionsOptions<TPrincipal extends object | undefined = undefined> extends Omit<IRelyingPartySessionsOptions<TPrincipal>, 'provider' | 'csrfKey' | 'csrfLabel' | 'cookieNames' | 'cookieSessions' | 'bearer'> {
|
|
88
|
+
cookieSessions: false;
|
|
89
|
+
/** every bearer session is a provider login */
|
|
90
|
+
provider: IOidcProvider;
|
|
91
|
+
bearer: IRelyingPartyBearerOptions;
|
|
92
|
+
csrfKey?: never;
|
|
93
|
+
csrfLabel?: never;
|
|
94
|
+
cookieNames?: never;
|
|
95
|
+
}
|
|
66
96
|
/**
|
|
67
97
|
* The relying-party session layer: provider logins through the authorization
|
|
68
98
|
* code flow with PKCE, HttpOnly cookie sessions with a session-bound CSRF
|
|
69
99
|
* token, provider tokens sealed at rest and rotated under a cross-replica
|
|
70
100
|
* lock, and session ends that hand the tokens back.
|
|
71
101
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
102
|
+
* With `cookieSessions: false` it runs bearer hand-off mode alone and never
|
|
103
|
+
* touches a cookie (`IRelyingPartyBearerOnlySessionsOptions`).
|
|
104
|
+
*
|
|
105
|
+
* Nothing here runs on a timer: expired login attempts, bearer state and
|
|
106
|
+
* ended sessions are swept one bounded batch at a time when a login starts or
|
|
107
|
+
* the application opens a session, and the only timer — the revocation
|
|
108
|
+
* budget — is unreferenced and cleared on every path. Every session comes
|
|
109
|
+
* from a login start or from `openSession`, and each of those sweeps a batch
|
|
110
|
+
* of at least one first, so removal keeps pace with creation and the ended
|
|
111
|
+
* sessions kept stay bounded. Nothing here does I/O while it is constructed,
|
|
75
112
|
* so it is built before the database connects.
|
|
76
113
|
*
|
|
77
114
|
* `TPrincipal` is what a `principals.resolve` answers; with `isActive`
|
|
@@ -85,9 +122,11 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
85
122
|
readonly intentCookieName: string;
|
|
86
123
|
readonly loginPathPrefix: string;
|
|
87
124
|
readonly sessionMaxAgeSeconds: number;
|
|
88
|
-
constructor(optionsArg: IRelyingPartySessionsOptions<TPrincipal>);
|
|
125
|
+
constructor(optionsArg: IRelyingPartySessionsOptions<TPrincipal> | IRelyingPartyBearerOnlySessionsOptions<TPrincipal>);
|
|
89
126
|
/** Whether provider logins are offered at all. */
|
|
90
127
|
get providerLoginEnabled(): boolean;
|
|
128
|
+
/** Whether cookie sessions are offered; `false` only in bearer-only mode (`cookieSessions: false`). */
|
|
129
|
+
get cookieSessionsEnabled(): boolean;
|
|
91
130
|
/** Whether bearer hand-off mode is offered. */
|
|
92
131
|
get bearerLoginEnabled(): boolean;
|
|
93
132
|
/** The return targets bearer clients may name, per kind, as configured; `undefined` without bearer mode. */
|
|
@@ -109,7 +148,11 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
109
148
|
principalId: string;
|
|
110
149
|
maxAgeSeconds?: number;
|
|
111
150
|
}): Promise<IRelyingPartySessionOpening>;
|
|
112
|
-
/**
|
|
151
|
+
/**
|
|
152
|
+
* The live session behind the session cookie, or `null`. A read touches it
|
|
153
|
+
* at most once a minute. Always `null` in bearer-only mode, which reads no
|
|
154
|
+
* cookie.
|
|
155
|
+
*/
|
|
113
156
|
resolveCookieSession(cookieHeaderArg: string | null | undefined): Promise<IResolvedRelyingPartySession<TPrincipal> | null>;
|
|
114
157
|
/**
|
|
115
158
|
* Re-checks a session by its id with the same strength as a cookie request:
|
|
@@ -142,6 +185,16 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
142
185
|
endSessionsOfPrincipal(principalIdArg: string, optionsArg?: {
|
|
143
186
|
keepSessionId?: string;
|
|
144
187
|
}): Promise<number>;
|
|
188
|
+
/**
|
|
189
|
+
* One page of a principal's live sessions, newest first: the ones neither
|
|
190
|
+
* ended nor expired, and none at all while the principal is not active —
|
|
191
|
+
* exactly the sessions `isSessionLive` confirms. Pass the page's
|
|
192
|
+
* `nextCursor` as `cursor` to read the next one; the last page has none.
|
|
193
|
+
* The cursor is opaque, and one this method did not answer is refused with
|
|
194
|
+
* `invalid_sessions_cursor`. A session opened while the pages are read is
|
|
195
|
+
* listed only when it sorts after the cursor; none is listed twice.
|
|
196
|
+
*/
|
|
197
|
+
sessionsOfPrincipal(principalIdArg: string, optionsArg?: IRelyingPartySessionsPageOptions): Promise<IRelyingPartySessionsPage>;
|
|
145
198
|
clearSessionCookie(): string;
|
|
146
199
|
clearIntentCookie(): string;
|
|
147
200
|
/**
|
|
@@ -235,8 +288,25 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
235
288
|
* is unknown — is rotated first. The session has to belong to
|
|
236
289
|
* `expectedPrincipalIdArg`, so a credential is never evaluated with another
|
|
237
290
|
* person's tokens.
|
|
291
|
+
*
|
|
292
|
+
* With `rejectedAccessToken` (`IAuthorityTokenSource`) the call rotates the
|
|
293
|
+
* session's token whatever is stored, and only a rotation that it starts
|
|
294
|
+
* marks its answer `rotatedAfterRejection`: one that started before it, in
|
|
295
|
+
* this process or another replica's, says nothing about the rejection, so
|
|
296
|
+
* the call awaits it and throws `authority_unavailable`. A refused rotation
|
|
297
|
+
* ends the session (`refresh_token_refused`) and throws
|
|
298
|
+
* `authority_login_required`. A session without a refresh token has nothing
|
|
299
|
+
* to rotate with: it throws `authority_unavailable`, or ends as
|
|
300
|
+
* `access_token_unusable` when its token is dead.
|
|
301
|
+
*/
|
|
302
|
+
liveProviderToken(sessionIdArg: string, expectedPrincipalIdArg: string, optionsArg?: {
|
|
303
|
+
rejectedAccessToken?: string;
|
|
304
|
+
}): Promise<IProviderToken>;
|
|
305
|
+
/**
|
|
306
|
+
* One rotation of the session in this process at a time. A forced call that
|
|
307
|
+
* finds one running waits for it, so a refusal still ends it, and is
|
|
308
|
+
* unavailable otherwise: that rotation started before the call.
|
|
238
309
|
*/
|
|
239
|
-
liveProviderToken(sessionIdArg: string, expectedPrincipalIdArg: string): Promise<IProviderToken>;
|
|
240
310
|
private refreshProviderToken;
|
|
241
311
|
private runProviderRefresh;
|
|
242
312
|
/**
|
|
@@ -246,6 +316,7 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
246
316
|
*/
|
|
247
317
|
private tokenAfterForeignRefresh;
|
|
248
318
|
private requireProvider;
|
|
319
|
+
private requireCookieSessions;
|
|
249
320
|
private requireBearer;
|
|
250
321
|
private checkLoginOptions;
|
|
251
322
|
/** An unsaved attempt with its state, nonce and sealed verifier; the caller binds it and names where it returns. */
|
|
@@ -282,6 +353,19 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
282
353
|
private endUnclaimedHandoff;
|
|
283
354
|
/** Revokes a session that was never handed out and erases its sealed tokens. */
|
|
284
355
|
private discardUnopenedSession;
|
|
356
|
+
/**
|
|
357
|
+
* Revokes a session not revoked yet and erases its sealed tokens; answers
|
|
358
|
+
* the document as it was before, `null` when it was over already. Its
|
|
359
|
+
* expiry comes forward to the revocation, never later, so the sweep finds
|
|
360
|
+
* an ended session by its expiry alone and `revokedAt` keeps when and that
|
|
361
|
+
* it was ended. Two conditional writes keep the earlier of the two times:
|
|
362
|
+
* the first ends a session within its expiry, the second one past it. A
|
|
363
|
+
* crash between them leaves an expired row unrevoked, which reads as over
|
|
364
|
+
* and is swept; a row revoked before 19.4.0 kept its later expiry, which is
|
|
365
|
+
* harmless because every reader checks `revokedAt` or reads live rows only,
|
|
366
|
+
* and it ages out.
|
|
367
|
+
*/
|
|
368
|
+
private revokeSessionDocument;
|
|
285
369
|
/**
|
|
286
370
|
* Tells the application a session ended. Its hook never stands between the
|
|
287
371
|
* local revocation and the provider revocation: a throw or a rejection is
|
|
@@ -326,6 +410,17 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
326
410
|
* sign-in.
|
|
327
411
|
*/
|
|
328
412
|
private sweepBearerState;
|
|
413
|
+
/**
|
|
414
|
+
* Removes sessions an hour past their expiry, oldest first, one bounded
|
|
415
|
+
* page per login start and per session the application opens. An ended
|
|
416
|
+
* session's expiry is its revocation at the latest, so the expiry index
|
|
417
|
+
* finds expired and revoked sessions alike. Each of them ended already: the
|
|
418
|
+
* row goes without an end, a hook or a provider call. A row is deleted only
|
|
419
|
+
* while its expiry is still past the cutoff, so a row whose expiry moved
|
|
420
|
+
* after the page was read stays. A sweep that cannot run never blocks a
|
|
421
|
+
* sign-in.
|
|
422
|
+
*/
|
|
423
|
+
private sweepEndedSessions;
|
|
329
424
|
/**
|
|
330
425
|
* Reports one diagnostic. Every cleanup step reports through here, so a
|
|
331
426
|
* throwing sink must not end it: the event and the sink's failure go to
|