@idp.global/sdk 19.5.0 → 19.6.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 +34 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_relyingparty/classes.idpoidcprovider.d.ts +69 -11
- package/dist_ts_relyingparty/classes.idpoidcprovider.js +127 -17
- package/dist_ts_relyingparty/classes.relyingpartysessions.d.ts +67 -12
- package/dist_ts_relyingparty/classes.relyingpartysessions.js +179 -41
- package/dist_ts_relyingparty/classes.rpmodels.d.ts +21 -4
- package/dist_ts_relyingparty/classes.rpmodels.js +35 -8
- package/dist_ts_relyingparty/helpers.cookies.d.ts +6 -0
- package/dist_ts_relyingparty/helpers.cookies.js +8 -1
- package/dist_ts_relyingparty/interfaces.d.ts +31 -0
- package/dist_ts_relyingparty/testing.js +8 -4
- package/package.json +3 -3
- package/readme.md +132 -32
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts_relyingparty/classes.idpoidcprovider.ts +183 -17
- package/ts_relyingparty/classes.relyingpartysessions.ts +225 -44
- package/ts_relyingparty/classes.rpmodels.ts +27 -4
- package/ts_relyingparty/helpers.cookies.ts +13 -0
- package/ts_relyingparty/interfaces.ts +32 -0
- package/ts_relyingparty/testing.ts +7 -3
package/changelog.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-11-11 - 19.6.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- a lost refresh answer no longer signs the person out: `bearer.refreshReuseGraceSeconds` (relyingparty)
|
|
8
|
+
- A spent bearer refresh token that comes back within the window of its rotation (60 seconds by default, 0 turns it off, at most 300; the constructor refuses anything else), while its successor was never presented, revokes that successor and answers a new pair; the `bearer_refresh_reissued` event reports it. Presented means the successor's access token authenticated a request or its refresh token was sent to `bearer/refresh`; the first presentation is recorded on the token generation (`firstUsedAt`), and a rotation names its successor (`successorId`). Only hashes are stored, so the lost pair is replaced, never repeated.
|
|
9
|
+
- Once the successor was presented, after the window (counted from the rotation, however often the retry's answer is lost too), and for the second of two retries at once, the spent token is reuse and ends the session as before (`refresh_token_reused`). Generations stored before this release carry neither field and are handled as before.
|
|
10
|
+
- `bearer/logout` (`endBearerSession`) judges a spent refresh token as the refresh does: one that would be a lost answer there ends the session as a `logout`, so signing out after a lost refresh answer reports no `bearer_credential_reused` and no `refresh_token_reused`.
|
|
11
|
+
- The browser client needs no change: after a lost refresh its next refresh with the stored pair recovers within the window. A relying party that wants the strict rotation of 19.5.0 sets `refreshReuseGraceSeconds: 0`.
|
|
12
|
+
- `TRelyingPartyEventName` gains `bearer_refresh_reissued`; a consumer that switches over it exhaustively adds the case.
|
|
13
|
+
- The first request with each new access token now writes once to record its presentation.
|
|
14
|
+
- a cookie policy for framed applications: `cookiePolicy: { sameSite, partitioned }` (relyingparty)
|
|
15
|
+
- `sameSite` is `'Lax'` (the default, unchanged) or `'None'`; `partitioned: true` adds the CHIPS `Partitioned` attribute and is valid only with `'None'`. One policy goes on the session and the intent cookie, on every `Set-Cookie` that sets or clears them: the login start, the opened session, `openSession`, `clearSessionCookie` and `clearIntentCookie`.
|
|
16
|
+
- The constructor refuses `partitioned` without `sameSite: 'None'`, `sameSite: 'None'` on an http `publicOrigin` (a `SameSite=None` cookie must be `Secure`), any other value, and `cookiePolicy` in bearer-only mode. `sessions.cookiePolicy` answers the resolved policy.
|
|
17
|
+
- `serializeCookie` takes `partitioned` and throws when it is given without `secure`.
|
|
18
|
+
- typed provider errors: `OidcProviderError` with `code` and `oauthError` (relyingparty)
|
|
19
|
+
- An application classifies a failure of the provider half without importing openid-client. `code` (`TOidcProviderErrorCode`, listed in `OIDC_PROVIDER_ERROR_CODES`) is `token_exchange_refused`, `login_mismatch`, `invalid_response`, `provider_unreachable` or `refresh_refused`; `oauthError` is the provider's own OAuth error code when it sent one, such as `invalid_grant`, kept only when it is a short token and never with its description.
|
|
20
|
+
- `OidcCompletionError`, `OidcRefreshRefusedError` and `OidcAuthorityUnavailableError` now extend `OidcProviderError`; their names, `stage`, `reason` and constructors stay, and `OidcCompletionError` takes the code as an optional third argument (without it, the code is read from the cause). `IdpOidcProvider` maps openid-client's failures to the codes, and the provider double of `/relyingparty/testing` answers with the codes idp.global's would.
|
|
21
|
+
- `IdpOidcProvider.completeAuthorization` refuses a callback whose one `state` is not the login's (`login_mismatch`) before it asks the provider. A refresh whose answer fails openid-client's checks is now `OidcAuthorityUnavailableError` with the reason `invalid_response` instead of `unavailable`; both fail closed as before.
|
|
22
|
+
|
|
23
|
+
### Fixes
|
|
24
|
+
|
|
25
|
+
- a swept session takes its bearer rows with it, and `endSessionsOfPrincipal` leaves expired sessions alone (relyingparty)
|
|
26
|
+
- The session sweep now deletes a session's bearer hand-offs and token generations by `sessionId` before the session row. Before, a session revoked early was swept an hour after its revocation while its generations stayed until an hour after its original expiry, with no row left that named the principal, so `eraseSessionsOfPrincipal` could not reach them. A sweep that fails between the two leaves the session row, and the next sweep finishes it.
|
|
27
|
+
- The bearer hand-off and bearer token models declare a `sessionId` index, which the sweep and `eraseSessionsOfPrincipal` read; it is built on first use like the `expiresAt` index. On the test suite's engine a token write cost 3.68 instead of 3.22 ms in memory and 9.38 instead of 9.23 ms on file storage, and a delete by session took 5 instead of 54 ms (4,000 rows, memory) and 16 instead of 88 ms (600 rows, file).
|
|
28
|
+
- `endSessionsOfPrincipal` reads only sessions that have not expired: an expired one is over already and is no longer revoked, handed back to the provider or counted. `eraseSessionsOfPrincipal` still ends it.
|
|
29
|
+
- ID tokens are verified against idp.global's signing keys (relyingparty)
|
|
30
|
+
- Before, `IdpOidcProvider` accepted the ID token of a code exchange or a refresh on the trust of the TLS connection to the token endpoint alone and never checked its signature. Discovery now turns on openid-client's `enableNonRepudiationChecks`, so every ID token of both grants is checked against the issuer's `jwks_uri` (RS256), fetched through the provider's own transport (`trustedCaPem` or `fetch` included) and cached by openid-client.
|
|
31
|
+
- A code exchange whose ID token is signed by a key outside the JWKS fails as `OidcCompletionError` at the `token_exchange` stage, and a refresh as `OidcAuthorityUnavailableError`, which ends nothing and fails closed. The first login after a start fetches the JWKS once more.
|
|
32
|
+
|
|
33
|
+
### Maintenance
|
|
34
|
+
|
|
35
|
+
- release tooling: `@git.zone/tsrepo` ^1.1.1 → ^2.1.0 (2.0.0 makes `@push.rocks/smartmongo` an optional peer of its tapbundle; the sdk's tests do not call `createSmartmongo()`), `@types/node` 26.6.5 → 26.6.6 and pnpm 12.14.0 → 12.17.0; the re-resolved tooling (`@push.rocks/smartfile` 13.2.4 with `@push.rocks/smartcrypto` 3.1.0) no longer installs `node-forge`; `brace-expansion` 2.1.2 → 2.1.7 (through `minimatch` 9.0.9 in the production closure) clears its high advisories.
|
|
36
|
+
|
|
3
37
|
## 2026-10-26 - 19.5.0
|
|
4
38
|
|
|
5
39
|
### Features
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@idp.global/sdk',
|
|
6
|
-
version: '19.
|
|
6
|
+
version: '19.6.0',
|
|
7
7
|
description: 'Reusable browser and server SDK for idp.global authentication.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxpQkFBaUI7SUFDdkIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLGdFQUFnRTtDQUM5RSxDQUFBIn0=
|
|
@@ -56,22 +56,80 @@ export interface IOidcRefreshedTokens {
|
|
|
56
56
|
/** epoch milliseconds; `0` when the token response named no lifetime */
|
|
57
57
|
accessTokenExpiresAt: number;
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* What failed when the provider was asked, as an application tells the cases
|
|
61
|
+
* apart; never why access was refused, which only an authority answer says.
|
|
62
|
+
*/
|
|
63
|
+
export type TOidcProviderErrorCode =
|
|
64
|
+
/**
|
|
65
|
+
* The provider refused the login: an OAuth error in the callback, for the
|
|
66
|
+
* code at the token endpoint, or for its token at UserInfo. `oauthError`
|
|
67
|
+
* names it, such as `invalid_grant` for a code that was used or expired.
|
|
68
|
+
*/
|
|
69
|
+
'token_exchange_refused'
|
|
70
|
+
/**
|
|
71
|
+
* The callback or its ID token is not this login's: a `state` that is not
|
|
72
|
+
* the login's, or an ID token claim that does not match it (the nonce, and
|
|
73
|
+
* likewise the issuer, the audience or the authorized party).
|
|
74
|
+
*/
|
|
75
|
+
| 'login_mismatch'
|
|
76
|
+
/**
|
|
77
|
+
* The provider answered outside its contract: an ID token whose signature
|
|
78
|
+
* does not verify against the JWKS or that has expired, no subject, another
|
|
79
|
+
* subject at UserInfo, or a body that is no OAuth answer.
|
|
80
|
+
*/
|
|
81
|
+
| 'invalid_response'
|
|
82
|
+
/** The provider could not be asked: no answer in time, a transport failure, a 5xx, or no discovery yet. */
|
|
83
|
+
| 'provider_unreachable'
|
|
84
|
+
/** The refresh grant answered `invalid_grant`: the refresh family is revoked, expired or was reused. */
|
|
85
|
+
| 'refresh_refused';
|
|
86
|
+
export declare const OIDC_PROVIDER_ERROR_CODES: readonly TOidcProviderErrorCode[];
|
|
87
|
+
/**
|
|
88
|
+
* Every failure of the provider this module throws: its `code` says which
|
|
89
|
+
* case it is, `oauthError` the provider's own OAuth error code where it sent
|
|
90
|
+
* one (a short token, never its description). An application classifies a
|
|
91
|
+
* failure by these and never by openid-client's classes; `cause` keeps the
|
|
92
|
+
* original for a debugger, not for a log line.
|
|
93
|
+
*/
|
|
94
|
+
export declare class OidcProviderError extends Error {
|
|
95
|
+
readonly code: TOidcProviderErrorCode;
|
|
96
|
+
readonly oauthError?: string;
|
|
97
|
+
constructor(messageArg: string, detailArg: {
|
|
98
|
+
code: TOidcProviderErrorCode;
|
|
99
|
+
oauthError?: string;
|
|
100
|
+
}, causeArg?: unknown);
|
|
101
|
+
}
|
|
59
102
|
/** Why an observation or a refresh could not be made; never why access was refused. */
|
|
60
103
|
export type TOidcAuthorityFailure = 'unavailable' | 'invalid_response';
|
|
61
|
-
/**
|
|
62
|
-
|
|
104
|
+
/**
|
|
105
|
+
* The provider could not be asked, or did not answer in its own contract. The
|
|
106
|
+
* caller fails closed on it. `code` is `provider_unreachable` or
|
|
107
|
+
* `invalid_response`, after `reason`.
|
|
108
|
+
*/
|
|
109
|
+
export declare class OidcAuthorityUnavailableError extends OidcProviderError {
|
|
63
110
|
readonly reason: TOidcAuthorityFailure;
|
|
64
111
|
constructor(reason: TOidcAuthorityFailure, causeArg?: unknown);
|
|
65
112
|
}
|
|
66
|
-
/**
|
|
67
|
-
|
|
113
|
+
/**
|
|
114
|
+
* The provider refused the refresh with `invalid_grant`: the refresh family is
|
|
115
|
+
* revoked, expired or was reused. `code` is `refresh_refused`.
|
|
116
|
+
*/
|
|
117
|
+
export declare class OidcRefreshRefusedError extends OidcProviderError {
|
|
68
118
|
constructor(causeArg?: unknown);
|
|
69
119
|
}
|
|
70
120
|
export type TOidcTokenHint = 'access_token' | 'refresh_token';
|
|
71
121
|
export type TOidcCompletionFailureStage = 'token_exchange' | 'token_validation' | 'userinfo';
|
|
72
|
-
|
|
122
|
+
/**
|
|
123
|
+
* A login the provider half could not complete. `stage` says where it
|
|
124
|
+
* stopped, `code` what it was; without a `detailArg` the code is read from
|
|
125
|
+
* the cause, an openid-client failure.
|
|
126
|
+
*/
|
|
127
|
+
export declare class OidcCompletionError extends OidcProviderError {
|
|
73
128
|
readonly stage: TOidcCompletionFailureStage;
|
|
74
|
-
constructor(stage: TOidcCompletionFailureStage, causeArg: unknown
|
|
129
|
+
constructor(stage: TOidcCompletionFailureStage, causeArg: unknown, detailArg?: {
|
|
130
|
+
code: TOidcProviderErrorCode;
|
|
131
|
+
oauthError?: string;
|
|
132
|
+
});
|
|
75
133
|
}
|
|
76
134
|
/**
|
|
77
135
|
* What the session layer needs from the provider. `IdpOidcProvider` is the
|
|
@@ -115,7 +173,7 @@ export interface IIdpOidcProviderOptions {
|
|
|
115
173
|
/** the registered callback, on the application's public origin */
|
|
116
174
|
redirectUri: URL;
|
|
117
175
|
scopes?: string;
|
|
118
|
-
/** deadline of discovery, token, UserInfo, refresh and revocation requests */
|
|
176
|
+
/** deadline of discovery, token, JWKS, UserInfo, refresh and revocation requests */
|
|
119
177
|
requestTimeoutSeconds?: number;
|
|
120
178
|
/** deadline of one introspection; the introspection client's default applies when absent */
|
|
121
179
|
introspectionTimeoutMs?: number;
|
|
@@ -129,7 +187,7 @@ export interface IIdpOidcProviderOptions {
|
|
|
129
187
|
trustedCaPem?: string | readonly string[];
|
|
130
188
|
/**
|
|
131
189
|
* Advanced: the fetch that carries every request of this provider —
|
|
132
|
-
* discovery, token, UserInfo, refresh, revocation and introspection.
|
|
190
|
+
* discovery, token, JWKS, UserInfo, refresh, revocation and introspection.
|
|
133
191
|
* It owns the transport's trust decisions; https-only still holds. Not
|
|
134
192
|
* combined with `trustedCaPem`.
|
|
135
193
|
*/
|
|
@@ -144,9 +202,9 @@ export declare const readOrganizationClaims: (valueArg: unknown) => IOidcOrganiz
|
|
|
144
202
|
/**
|
|
145
203
|
* The relying-party side of the authorization code flow with S256 PKCE on
|
|
146
204
|
* `openid-client`, in the profile idp.global supports: code responses, S256
|
|
147
|
-
* challenges, RS256 ID tokens
|
|
148
|
-
*
|
|
149
|
-
* `OidcIntrospectionClient`.
|
|
205
|
+
* challenges, RS256 ID tokens whose signature is verified against the
|
|
206
|
+
* issuer's JWKS, and `client_secret_basic` for a confidential client. Live
|
|
207
|
+
* organization authority is observed with the sdk's `OidcIntrospectionClient`.
|
|
150
208
|
*/
|
|
151
209
|
export declare class IdpOidcProvider implements IOidcProvider {
|
|
152
210
|
#private;
|
|
@@ -2,26 +2,123 @@ import * as plugins from './plugins.js';
|
|
|
2
2
|
import { OidcIntrospectionClient, OidcIntrospectionError, } from '../dist_ts_server/classes.oidc-introspection-client.js';
|
|
3
3
|
import { createTrustedCaFetch } from '../dist_ts_server/helpers.trusted-ca-fetch.js';
|
|
4
4
|
export const OIDC_PROMPTS = ['none', 'login', 'consent'];
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export const OIDC_PROVIDER_ERROR_CODES = [
|
|
6
|
+
'token_exchange_refused',
|
|
7
|
+
'login_mismatch',
|
|
8
|
+
'invalid_response',
|
|
9
|
+
'provider_unreachable',
|
|
10
|
+
'refresh_refused',
|
|
11
|
+
];
|
|
12
|
+
/** An OAuth error code is a short token; anything else a provider sends there is dropped, never kept. */
|
|
13
|
+
const OAUTH_ERROR_PATTERN = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
14
|
+
const oauthErrorOf = (valueArg) => typeof valueArg === 'string' && OAUTH_ERROR_PATTERN.test(valueArg) ? valueArg : undefined;
|
|
15
|
+
/** The OAuth error and HTTP status of an openid-client failure that is the provider's own answer; `null` for any other failure. */
|
|
16
|
+
const providerAnswerOf = (errorArg) => {
|
|
17
|
+
const openidClient = plugins.openidClient;
|
|
18
|
+
if (errorArg instanceof openidClient.ResponseBodyError) {
|
|
19
|
+
return { oauthError: oauthErrorOf(errorArg.error), status: errorArg.status };
|
|
20
|
+
}
|
|
21
|
+
if (errorArg instanceof openidClient.AuthorizationResponseError) {
|
|
22
|
+
return { oauthError: oauthErrorOf(errorArg.error) };
|
|
23
|
+
}
|
|
24
|
+
if (errorArg instanceof openidClient.WWWAuthenticateChallengeError) {
|
|
25
|
+
return { oauthError: oauthErrorOf(errorArg.cause[0]?.parameters.error), status: errorArg.status };
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
28
|
+
};
|
|
29
|
+
/** openid-client's codes (`ClientError.code`) for a provider that did not answer in time or within HTTP's own contract. */
|
|
30
|
+
const UNREACHABLE_CLIENT_ERROR_CODES = ['OAUTH_TIMEOUT', 'OAUTH_ABORT', 'OAUTH_RESPONSE_IS_NOT_CONFORM'];
|
|
31
|
+
/** openid-client's code for a JWT claim that is not the expected one: the nonce, the issuer, the audience or the authorized party. */
|
|
32
|
+
const JWT_CLAIM_COMPARISON_CODE = 'OAUTH_JWT_CLAIM_COMPARISON_FAILED';
|
|
33
|
+
/**
|
|
34
|
+
* The class of an openid-client failure of the code exchange or of UserInfo.
|
|
35
|
+
* The provider's own OAuth error answer is a refusal, or unreachable on a 5xx;
|
|
36
|
+
* a claim that does not match is not this login's; every other failure of
|
|
37
|
+
* openid-client's checks is an invalid response; and anything else (a
|
|
38
|
+
* transport failure is fetch's `TypeError`) is an unreachable provider.
|
|
39
|
+
*/
|
|
40
|
+
const classifyCompletionFailure = (errorArg) => {
|
|
41
|
+
if (errorArg instanceof OidcProviderError) {
|
|
42
|
+
return { code: errorArg.code, oauthError: errorArg.oauthError };
|
|
43
|
+
}
|
|
44
|
+
const answer = providerAnswerOf(errorArg);
|
|
45
|
+
if (answer) {
|
|
46
|
+
const code = answer.status !== undefined && answer.status >= 500
|
|
47
|
+
? 'provider_unreachable'
|
|
48
|
+
: 'token_exchange_refused';
|
|
49
|
+
return { code, oauthError: answer.oauthError };
|
|
50
|
+
}
|
|
51
|
+
if (errorArg instanceof plugins.openidClient.ClientError) {
|
|
52
|
+
if (errorArg.code === JWT_CLAIM_COMPARISON_CODE) {
|
|
53
|
+
return { code: 'login_mismatch' };
|
|
54
|
+
}
|
|
55
|
+
return { code: errorArg.code !== undefined && UNREACHABLE_CLIENT_ERROR_CODES.includes(errorArg.code) ? 'provider_unreachable' : 'invalid_response' };
|
|
56
|
+
}
|
|
57
|
+
return { code: 'provider_unreachable' };
|
|
58
|
+
};
|
|
59
|
+
/** Why a refresh could not be made: openid-client's checks failed on the answer, or the provider could not be asked. */
|
|
60
|
+
const refreshFailureReasonOf = (errorArg) => errorArg instanceof plugins.openidClient.ClientError
|
|
61
|
+
&& !(errorArg.code !== undefined && UNREACHABLE_CLIENT_ERROR_CODES.includes(errorArg.code))
|
|
62
|
+
? 'invalid_response'
|
|
63
|
+
: 'unavailable';
|
|
64
|
+
/**
|
|
65
|
+
* Every failure of the provider this module throws: its `code` says which
|
|
66
|
+
* case it is, `oauthError` the provider's own OAuth error code where it sent
|
|
67
|
+
* one (a short token, never its description). An application classifies a
|
|
68
|
+
* failure by these and never by openid-client's classes; `cause` keeps the
|
|
69
|
+
* original for a debugger, not for a log line.
|
|
70
|
+
*/
|
|
71
|
+
export class OidcProviderError extends Error {
|
|
72
|
+
code;
|
|
73
|
+
oauthError;
|
|
74
|
+
constructor(messageArg, detailArg, causeArg) {
|
|
75
|
+
super(messageArg, { cause: causeArg });
|
|
76
|
+
this.name = 'OidcProviderError';
|
|
77
|
+
if (!OIDC_PROVIDER_ERROR_CODES.includes(detailArg?.code)) {
|
|
78
|
+
throw new TypeError('OidcProviderError needs one of OIDC_PROVIDER_ERROR_CODES');
|
|
79
|
+
}
|
|
80
|
+
this.code = detailArg.code;
|
|
81
|
+
const oauthError = oauthErrorOf(detailArg.oauthError);
|
|
82
|
+
if (oauthError !== undefined) {
|
|
83
|
+
this.oauthError = oauthError;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The provider could not be asked, or did not answer in its own contract. The
|
|
89
|
+
* caller fails closed on it. `code` is `provider_unreachable` or
|
|
90
|
+
* `invalid_response`, after `reason`.
|
|
91
|
+
*/
|
|
92
|
+
export class OidcAuthorityUnavailableError extends OidcProviderError {
|
|
7
93
|
reason;
|
|
8
94
|
constructor(reason, causeArg) {
|
|
9
|
-
super('The identity provider could not be observed', {
|
|
95
|
+
super('The identity provider could not be observed', {
|
|
96
|
+
code: reason === 'invalid_response' ? 'invalid_response' : 'provider_unreachable',
|
|
97
|
+
oauthError: providerAnswerOf(causeArg)?.oauthError,
|
|
98
|
+
}, causeArg);
|
|
10
99
|
this.reason = reason;
|
|
11
100
|
this.name = 'OidcAuthorityUnavailableError';
|
|
12
101
|
}
|
|
13
102
|
}
|
|
14
|
-
/**
|
|
15
|
-
|
|
103
|
+
/**
|
|
104
|
+
* The provider refused the refresh with `invalid_grant`: the refresh family is
|
|
105
|
+
* revoked, expired or was reused. `code` is `refresh_refused`.
|
|
106
|
+
*/
|
|
107
|
+
export class OidcRefreshRefusedError extends OidcProviderError {
|
|
16
108
|
constructor(causeArg) {
|
|
17
|
-
super('The identity provider refused the refresh', {
|
|
109
|
+
super('The identity provider refused the refresh', { code: 'refresh_refused', oauthError: 'invalid_grant' }, causeArg);
|
|
18
110
|
this.name = 'OidcRefreshRefusedError';
|
|
19
111
|
}
|
|
20
112
|
}
|
|
21
|
-
|
|
113
|
+
/**
|
|
114
|
+
* A login the provider half could not complete. `stage` says where it
|
|
115
|
+
* stopped, `code` what it was; without a `detailArg` the code is read from
|
|
116
|
+
* the cause, an openid-client failure.
|
|
117
|
+
*/
|
|
118
|
+
export class OidcCompletionError extends OidcProviderError {
|
|
22
119
|
stage;
|
|
23
|
-
constructor(stage, causeArg) {
|
|
24
|
-
super('OIDC completion failed',
|
|
120
|
+
constructor(stage, causeArg, detailArg) {
|
|
121
|
+
super('OIDC completion failed', detailArg ?? classifyCompletionFailure(causeArg), causeArg);
|
|
25
122
|
this.stage = stage;
|
|
26
123
|
this.name = 'OidcCompletionError';
|
|
27
124
|
}
|
|
@@ -68,9 +165,9 @@ export const readOrganizationClaims = (valueArg) => {
|
|
|
68
165
|
/**
|
|
69
166
|
* The relying-party side of the authorization code flow with S256 PKCE on
|
|
70
167
|
* `openid-client`, in the profile idp.global supports: code responses, S256
|
|
71
|
-
* challenges, RS256 ID tokens
|
|
72
|
-
*
|
|
73
|
-
* `OidcIntrospectionClient`.
|
|
168
|
+
* challenges, RS256 ID tokens whose signature is verified against the
|
|
169
|
+
* issuer's JWKS, and `client_secret_basic` for a confidential client. Live
|
|
170
|
+
* organization authority is observed with the sdk's `OidcIntrospectionClient`.
|
|
74
171
|
*/
|
|
75
172
|
export class IdpOidcProvider {
|
|
76
173
|
requestTimeoutSeconds;
|
|
@@ -114,13 +211,18 @@ export class IdpOidcProvider {
|
|
|
114
211
|
}
|
|
115
212
|
const options = this.#options;
|
|
116
213
|
// the timeout and the fetch given to discovery apply to discovery itself
|
|
117
|
-
// and stay on the resolved configuration for every later request
|
|
214
|
+
// and stay on the resolved configuration for every later request.
|
|
215
|
+
// `enableNonRepudiationChecks` verifies the signature of every ID token the
|
|
216
|
+
// code grant and the refresh grant answer against the issuer's JWKS
|
|
217
|
+
// (`jwks_uri`, fetched through the same fetch), so an ID token is never
|
|
218
|
+
// accepted on the trust of the TLS connection alone
|
|
118
219
|
const configuration = await plugins.openidClient.discovery(options.issuer, options.clientId, {
|
|
119
220
|
client_secret: options.clientSecret,
|
|
120
221
|
token_endpoint_auth_method: 'client_secret_basic',
|
|
121
222
|
id_token_signed_response_alg: 'RS256',
|
|
122
223
|
}, plugins.openidClient.ClientSecretBasic(options.clientSecret), {
|
|
123
224
|
timeout: this.requestTimeoutSeconds,
|
|
225
|
+
execute: [plugins.openidClient.enableNonRepudiationChecks],
|
|
124
226
|
...(this.#fetch ? { [plugins.openidClient.customFetch]: this.#fetch } : {}),
|
|
125
227
|
});
|
|
126
228
|
const metadata = configuration.serverMetadata();
|
|
@@ -164,6 +266,11 @@ export class IdpOidcProvider {
|
|
|
164
266
|
});
|
|
165
267
|
}
|
|
166
268
|
async completeAuthorization(optionsArg) {
|
|
269
|
+
// the one state of the callback is the login's, or nothing is exchanged
|
|
270
|
+
const states = optionsArg.callbackUrl.searchParams.getAll('state');
|
|
271
|
+
if (states.length !== 1 || states[0] !== optionsArg.state) {
|
|
272
|
+
throw new OidcCompletionError('token_exchange', new Error('The callback state is not the state of this login'), { code: 'login_mismatch' });
|
|
273
|
+
}
|
|
167
274
|
let tokens;
|
|
168
275
|
try {
|
|
169
276
|
tokens = await plugins.openidClient.authorizationCodeGrant(this.configuration, optionsArg.callbackUrl, {
|
|
@@ -185,7 +292,7 @@ export class IdpOidcProvider {
|
|
|
185
292
|
subject = claims.sub;
|
|
186
293
|
}
|
|
187
294
|
catch (error) {
|
|
188
|
-
throw new OidcCompletionError('token_validation', error);
|
|
295
|
+
throw new OidcCompletionError('token_validation', error, { code: 'invalid_response' });
|
|
189
296
|
}
|
|
190
297
|
// UserInfo is the current view of profile and organization claims; the ID
|
|
191
298
|
// token proves the login. Both are read, and the subjects must agree.
|
|
@@ -197,7 +304,7 @@ export class IdpOidcProvider {
|
|
|
197
304
|
throw new OidcCompletionError('userinfo', error);
|
|
198
305
|
}
|
|
199
306
|
if (userInfo.sub !== subject) {
|
|
200
|
-
throw new OidcCompletionError('token_validation', new Error('The UserInfo subject does not match the ID token'));
|
|
307
|
+
throw new OidcCompletionError('token_validation', new Error('The UserInfo subject does not match the ID token'), { code: 'invalid_response' });
|
|
201
308
|
}
|
|
202
309
|
return {
|
|
203
310
|
subject,
|
|
@@ -263,7 +370,10 @@ export class IdpOidcProvider {
|
|
|
263
370
|
if (error instanceof plugins.openidClient.ResponseBodyError && error.error === 'invalid_grant') {
|
|
264
371
|
throw new OidcRefreshRefusedError(error);
|
|
265
372
|
}
|
|
266
|
-
|
|
373
|
+
// everything else fails closed: another OAuth error (`invalid_client` for a
|
|
374
|
+
// deactivated app) or a transport failure is unreachable, an answer that
|
|
375
|
+
// fails openid-client's checks (an ID token that does not verify) is invalid
|
|
376
|
+
throw new OidcAuthorityUnavailableError(refreshFailureReasonOf(error), error);
|
|
267
377
|
}
|
|
268
378
|
return {
|
|
269
379
|
accessToken: tokens.access_token,
|
|
@@ -272,4 +382,4 @@ export class IdpOidcProvider {
|
|
|
272
382
|
};
|
|
273
383
|
}
|
|
274
384
|
}
|
|
275
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5pZHBvaWRjcHJvdmlkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90c19yZWx5aW5ncGFydHkvY2xhc3Nlcy5pZHBvaWRjcHJvdmlkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixzQkFBc0IsR0FDdkIsTUFBTSxtREFBbUQsQ0FBQztBQUMzRCxPQUFPLEVBQUUsb0JBQW9CLEVBQW1CLE1BQU0sMENBQTBDLENBQUM7QUFLakcsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUEyQixDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFpRWpGLDZHQUE2RztBQUM3RyxNQUFNLE9BQU8sNkJBQThCLFNBQVEsS0FBSztJQUVwQyxNQUFNO0lBRHhCLFlBQ2tCLE1BQTZCLEVBQzdDLFFBQWtCO1FBRWxCLEtBQUssQ0FBQyw2Q0FBNkMsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO3NCQUgxRCxNQUFNO1FBSXRCLElBQUksQ0FBQyxJQUFJLEdBQUcsK0JBQStCLENBQUM7SUFDOUMsQ0FBQztDQUNGO0FBRUQsbUhBQW1IO0FBQ25ILE1BQU0sT0FBTyx1QkFBd0IsU0FBUSxLQUFLO0lBQ2hELFlBQVksUUFBa0I7UUFDNUIsS0FBSyxDQUFDLDJDQUEyQyxFQUFFLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDeEUsSUFBSSxDQUFDLElBQUksR0FBRyx5QkFBeUIsQ0FBQztJQUN4QyxDQUFDO0NBQ0Y7QUFNRCxNQUFNLE9BQU8sbUJBQW9CLFNBQVEsS0FBSztJQUUxQixLQUFLO0lBRHZCLFlBQ2tCLEtBQWtDLEVBQ2xELFFBQWlCO1FBRWpCLEtBQUssQ0FBQyx3QkFBd0IsRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO3FCQUhyQyxLQUFLO1FBSXJCLElBQUksQ0FBQyxJQUFJLEdBQUcscUJBQXFCLENBQUM7SUFDcEMsQ0FBQztDQUNGO0FBK0JEOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLDBDQUEwQyxDQUFDO0FBRWxGLE1BQU0sQ0FBQyxNQUFNLHdDQUF3QyxHQUFHLEVBQUUsQ0FBQztBQStCM0QsTUFBTSxjQUFjLEdBQUcsQ0FBQyxRQUFpQixFQUFzQixFQUFFLENBQy9ELE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFFM0Ysb0dBQW9HO0FBQ3BHLE1BQU0sUUFBUSxHQUFHLENBQUMsWUFBZ0MsRUFBVSxFQUFFLENBQzVELE9BQU8sWUFBWSxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxJQUFJLFlBQVksR0FBRyxDQUFDO0lBQ25GLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsR0FBRyxLQUFLO0lBQy9DLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFUjs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxRQUFpQixFQUE0QixFQUFFO0lBQ3BGLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDN0IsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBQ0QsTUFBTSxhQUFhLEdBQTZCLEVBQUUsQ0FBQztJQUNuRCxLQUFLLE1BQU0sS0FBSyxJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQzdCLElBQUksQ0FBQyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNoRSxTQUFTO1FBQ1gsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFHLEtBQWdDLENBQUM7UUFDbkQsTUFBTSxFQUFFLEdBQUcsY0FBYyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN4QyxNQUFNLElBQUksR0FBRyxjQUFjLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzVDLE1BQU0sSUFBSSxHQUFHLGNBQWMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQzFCLFNBQVM7UUFDWCxDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDO1lBQzFDLENBQUMsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLE9BQU8sRUFBcUIsRUFBRSxDQUFDLE9BQU8sT0FBTyxLQUFLLFFBQVEsQ0FBQztZQUNyRixDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ1AsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUNELE9BQU8sYUFBYSxDQUFDO0FBQ3ZCLENBQUMsQ0FBQztBQUVGOzs7Ozs7R0FNRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQ1YscUJBQXFCLENBQVM7SUFDckMsUUFBUSxDQUEwQjtJQUMzQyxxRUFBcUU7SUFDNUQsTUFBTSxDQUFjO0lBQzdCLGNBQWMsQ0FBc0M7SUFDcEQsY0FBYyxDQUEyQjtJQUV6QyxZQUFZLFVBQW1DO1FBQzdDLElBQUksQ0FBQyxDQUFDLFVBQVUsRUFBRSxNQUFNLFlBQVksR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FBQyxXQUFXLFlBQVksR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNyRixNQUFNLElBQUksS0FBSyxDQUFDLCtEQUErRCxDQUFDLENBQUM7UUFDbkYsQ0FBQztRQUNELElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO1lBQ3JGLE1BQU0sSUFBSSxLQUFLLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUMzRSxDQUFDO1FBQ0QsTUFBTSxPQUFPLEdBQUcsVUFBVSxDQUFDLHFCQUFxQixJQUFJLHdDQUF3QyxDQUFDO1FBQzdGLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE9BQU8sR0FBRyxDQUFDLElBQUksT0FBTyxHQUFHLEVBQUUsRUFBRSxDQUFDO1lBQ2xFLE1BQU0sSUFBSSxLQUFLLENBQUMsdUVBQXVFLENBQUMsQ0FBQztRQUMzRixDQUFDO1FBQ0QsSUFBSSxDQUFDLHFCQUFxQixHQUFHLE9BQU8sQ0FBQztRQUNyQyxJQUFJLFVBQVUsQ0FBQyxZQUFZLEtBQUssU0FBUyxJQUFJLFVBQVUsQ0FBQyxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDNUUsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1FBQzNFLENBQUM7UUFDRCxJQUFJLFVBQVUsQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLE9BQU8sVUFBVSxDQUFDLEtBQUssS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUM3RSxNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELElBQUksQ0FBQyxNQUFNLEdBQUcsVUFBVSxDQUFDLFlBQVksS0FBSyxTQUFTO1lBQ2pELENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFDO1lBQy9DLENBQUMsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDO1FBQ3JCLElBQUksQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO0lBQzdCLENBQUM7SUFFRCxJQUFZLGFBQWE7UUFDdkIsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FBQztJQUM3QixDQUFDO0lBRU0sS0FBSyxDQUFDLElBQUk7UUFDZixJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN4QixPQUFPO1FBQ1QsQ0FBQztRQUNELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7UUFDOUIseUVBQXlFO1FBQ3pFLGlFQUFpRTtRQUNqRSxNQUFNLGFBQWEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUN4RCxPQUFPLENBQUMsTUFBTSxFQUNkLE9BQU8sQ0FBQyxRQUFRLEVBQ2hCO1lBQ0UsYUFBYSxFQUFFLE9BQU8sQ0FBQyxZQUFZO1lBQ25DLDBCQUEwQixFQUFFLHFCQUFxQjtZQUNqRCw0QkFBNEIsRUFBRSxPQUFPO1NBQ3RDLEVBQ0QsT0FBTyxDQUFDLFlBQVksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLEVBQzVEO1lBQ0UsT0FBTyxFQUFFLElBQUksQ0FBQyxxQkFBcUI7WUFDbkMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1NBQzVFLENBQ0YsQ0FBQztRQUNGLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUNoRCxJQUFJLENBQUMsUUFBUSxDQUFDLHNCQUFzQixJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUN2RixNQUFNLElBQUksS0FBSyxDQUFDLDBEQUEwRCxDQUFDLENBQUM7UUFDOUUsQ0FBQztRQUNELElBQUksQ0FBQyxRQUFRLENBQUMsZ0NBQWdDLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDakUsTUFBTSxJQUFJLEtBQUssQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ2xFLENBQUM7UUFDRCxJQUNFLFFBQVEsQ0FBQyxxQ0FBcUM7ZUFDM0MsQ0FBQyxRQUFRLENBQUMscUNBQXFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUNwRSxDQUFDO1lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQyxzREFBc0QsQ0FBQyxDQUFDO1FBQzFFLENBQUM7UUFDRCxJQUFJLFFBQVEsQ0FBQyxxQkFBcUIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLENBQUMsb0JBQW9CLENBQUMsRUFBRSxDQUFDO1lBQ3JHLE1BQU0sSUFBSSxLQUFLLENBQUMsaUVBQWlFLENBQUMsQ0FBQztRQUNyRixDQUFDO1FBQ0QsSUFBSSxRQUFRLENBQUMscUJBQXFCLElBQUksQ0FBQyxRQUFRLENBQUMscUJBQXFCLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7WUFDaEcsc0VBQXNFO1lBQ3RFLE1BQU0sSUFBSSxLQUFLLENBQUMsNERBQTRELENBQUMsQ0FBQztRQUNoRixDQUFDO1FBQ0QsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLHVCQUF1QixDQUFDO1lBQ2hELE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU07WUFDN0IsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRO1lBQzFCLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtZQUNsQyxHQUFHLENBQUMsT0FBTyxDQUFDLHNCQUFzQixLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLHNCQUFzQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN0RyxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7U0FDL0MsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLGNBQWMsR0FBRyxhQUFhLENBQUM7SUFDdEMsQ0FBQztJQUVNLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxVQUFxQztRQUN0RSxNQUFNLGFBQWEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxZQUFZLENBQUMsMEJBQTBCLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3JHLE9BQU8sT0FBTyxDQUFDLFlBQVksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ3BFLFlBQVksRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxJQUFJO1lBQzVDLGFBQWEsRUFBRSxNQUFNO1lBQ3JCLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sSUFBSSx1QkFBdUI7WUFDdEQsY0FBYyxFQUFFLGFBQWE7WUFDN0IscUJBQXFCLEVBQUUsTUFBTTtZQUM3QixLQUFLLEVBQUUsVUFBVSxDQUFDLEtBQUs7WUFDdkIsS0FBSyxFQUFFLFVBQVUsQ0FBQyxLQUFLO1lBQ3ZCLEdBQUcsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztTQUM1RCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU0sS0FBSyxDQUFDLHFCQUFxQixDQUFDLFVBQWtDO1FBQ25FLElBQUksTUFBK0UsQ0FBQztRQUNwRixJQUFJLENBQUM7WUFDSCxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsWUFBWSxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsVUFBVSxDQUFDLFdBQVcsRUFBRTtnQkFDckcsZ0JBQWdCLEVBQUUsVUFBVSxDQUFDLFlBQVk7Z0JBQ3pDLGFBQWEsRUFBRSxVQUFVLENBQUMsS0FBSztnQkFDL0IsYUFBYSxFQUFFLFVBQVUsQ0FBQyxLQUFLO2dCQUMvQixlQUFlLEVBQUUsSUFBSTthQUN0QixDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sSUFBSSxtQkFBbUIsQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN6RCxDQUFDO1FBRUQsSUFBSSxPQUFlLENBQUM7UUFDcEIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUM7Z0JBQ2pCLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLENBQUMsQ0FBQztZQUMzRCxDQUFDO1lBQ0QsT0FBTyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUM7UUFDdkIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLElBQUksbUJBQW1CLENBQUMsa0JBQWtCLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDM0QsQ0FBQztRQUVELDBFQUEwRTtRQUMxRSxzRUFBc0U7UUFDdEUsSUFBSSxRQUF3RSxDQUFDO1FBQzdFLElBQUksQ0FBQztZQUNILFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxZQUFZLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLFlBQVksRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN4RyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sSUFBSSxtQkFBbUIsQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUNELElBQUksUUFBUSxDQUFDLEdBQUcsS0FBSyxPQUFPLEVBQUUsQ0FBQztZQUM3QixNQUFNLElBQUksbUJBQW1CLENBQUMsa0JBQWtCLEVBQUUsSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQyxDQUFDO1FBQ25ILENBQUM7UUFFRCxPQUFPO1lBQ0wsT0FBTztZQUNQLFdBQVcsRUFBRSxNQUFNLENBQUMsWUFBWTtZQUNoQyxHQUFHLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLEVBQUUsTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDdkUsb0JBQW9CLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7WUFDakQsS0FBSyxFQUFFLGNBQWMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO1lBQ3JDLGFBQWEsRUFBRSxRQUFRLENBQUMsY0FBYyxLQUFLLElBQUk7WUFDL0MsV0FBVyxFQUFFLGNBQWMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksY0FBYyxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQztZQUN6RixhQUFhLEVBQUUsc0JBQXNCLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsZUFBZSxDQUFDLENBQUM7U0FDOUUsQ0FBQztJQUNKLENBQUM7SUFFTSxLQUFLLENBQUMsV0FBVyxDQUFDLFFBQWdCLEVBQUUsT0FBdUI7UUFDaEUsTUFBTSxPQUFPLENBQUMsWUFBWSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLFFBQVEsRUFBRSxFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ3pHLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxVQUluQztRQUNDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDekIsNERBQTREO1lBQzVELDBEQUEwRDtZQUMxRCxNQUFNLElBQUksNkJBQTZCLENBQUMsYUFBYSxFQUFFLElBQUksS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUMsQ0FBQztRQUNoSCxDQUFDO1FBQ0QsSUFBSSxRQUFvRSxDQUFDO1FBQ3pFLElBQUksQ0FBQztZQUNILFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDO2dCQUM5QyxLQUFLLEVBQUUsVUFBVSxDQUFDLFdBQVc7Z0JBQzdCLE9BQU8sRUFBRSxVQUFVLENBQUMsT0FBTztnQkFDM0IsY0FBYyxFQUFFLFVBQVUsQ0FBQyxjQUFjO2FBQzFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxLQUFLLFlBQVksc0JBQXNCLEVBQUUsQ0FBQztnQkFDNUMsSUFBSSxLQUFLLENBQUMsSUFBSSxLQUFLLGlCQUFpQixFQUFFLENBQUM7b0JBQ3JDLGlFQUFpRTtvQkFDakUsdUNBQXVDO29CQUN2QyxNQUFNLEtBQUssQ0FBQztnQkFDZCxDQUFDO2dCQUNELE1BQU0sSUFBSSw2QkFBNkIsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzdELENBQUM7WUFDRCxNQUFNLElBQUksNkJBQTZCLENBQUMsYUFBYSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ2hFLENBQUM7UUFDRCxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3JCLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLENBQUMsRUFBRSxDQUFDO1FBQ3BELENBQUM7UUFDRCxPQUFPO1lBQ0wsTUFBTSxFQUFFLElBQUk7WUFDWixLQUFLLEVBQUUsUUFBUSxDQUFDLG9CQUFvQixDQUFDLEtBQUs7WUFDMUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxHQUFHLEdBQUcsS0FBSztTQUNoQyxDQUFDO0lBQ0osQ0FBQztJQUVELCtGQUErRjtJQUN4RixLQUFLLENBQUMsYUFBYSxDQUFDLGVBQXVCO1FBQ2hELElBQUksTUFBMEUsQ0FBQztRQUMvRSxJQUFJLENBQUM7WUFDSCxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsWUFBWSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsZUFBZSxDQUFDLENBQUM7UUFDN0YsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLEtBQUssWUFBWSxPQUFPLENBQUMsWUFBWSxDQUFDLGlCQUFpQixJQUFJLEtBQUssQ0FBQyxLQUFLLEtBQUssZUFBZSxFQUFFLENBQUM7Z0JBQy9GLE1BQU0sSUFBSSx1QkFBdUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUMzQyxDQUFDO1lBQ0QsTUFBTSxJQUFJLDZCQUE2QixDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsT0FBTztZQUNMLFdBQVcsRUFBRSxNQUFNLENBQUMsWUFBWTtZQUNoQyxHQUFHLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLEVBQUUsTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDdkUsb0JBQW9CLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7U0FDbEQsQ0FBQztJQUNKLENBQUM7Q0FDRiJ9
|
|
385
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5pZHBvaWRjcHJvdmlkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90c19yZWx5aW5ncGFydHkvY2xhc3Nlcy5pZHBvaWRjcHJvdmlkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixzQkFBc0IsR0FDdkIsTUFBTSxtREFBbUQsQ0FBQztBQUMzRCxPQUFPLEVBQUUsb0JBQW9CLEVBQW1CLE1BQU0sMENBQTBDLENBQUM7QUFLakcsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUEyQixDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUM7QUEwRmpGLE1BQU0sQ0FBQyxNQUFNLHlCQUF5QixHQUFzQztJQUMxRSx3QkFBd0I7SUFDeEIsZ0JBQWdCO0lBQ2hCLGtCQUFrQjtJQUNsQixzQkFBc0I7SUFDdEIsaUJBQWlCO0NBQ2xCLENBQUM7QUFFRix5R0FBeUc7QUFDekcsTUFBTSxtQkFBbUIsR0FBRyx3QkFBd0IsQ0FBQztBQUVyRCxNQUFNLFlBQVksR0FBRyxDQUFDLFFBQWlCLEVBQXNCLEVBQUUsQ0FDN0QsT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLG1CQUFtQixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFFNUYsbUlBQW1JO0FBQ25JLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxRQUFpQixFQUFtRCxFQUFFO0lBQzlGLE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUM7SUFDMUMsSUFBSSxRQUFRLFlBQVksWUFBWSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDdkQsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sRUFBRSxRQUFRLENBQUMs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
|
|
@@ -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, IRelyingPartyBearerHandoffOpening, IRelyingPartyBearerLoginRequest, IRelyingPartyBearerLoginStart, IRelyingPartyBearerOptions, IRelyingPartyBearerReturnTargets, IRelyingPartyBearerTokens, IRelyingPartyHooks, IRelyingPartyLiveSession, IRelyingPartyLoginOptions, IRelyingPartyLoginStart, IRelyingPartySession, IRelyingPartySessionOpening, IRelyingPartySessionsErasure, IRelyingPartySessionsPage, IRelyingPartySessionsPageOptions, IResolvedRelyingPartySession, TRelyingPartyPrincipals, TRelyingPartySessionEndReason } from './interfaces.js';
|
|
3
|
+
import type { IAuthorityTokenSource, IProviderToken, IRelyingPartyBearerDelivery, IRelyingPartyBearerHandoff, IRelyingPartyBearerHandoffOpening, IRelyingPartyBearerLoginRequest, IRelyingPartyBearerLoginStart, IRelyingPartyBearerOptions, IRelyingPartyBearerReturnTargets, IRelyingPartyBearerTokens, IRelyingPartyCookiePolicy, IRelyingPartyHooks, IRelyingPartyLiveSession, IRelyingPartyLoginOptions, IRelyingPartyLoginStart, IRelyingPartySession, IRelyingPartySessionOpening, IRelyingPartySessionsErasure, 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. */
|
|
@@ -17,6 +17,10 @@ export declare const RELYING_PARTY_MAX_SESSIONS_PAGE_LIMIT = 1000;
|
|
|
17
17
|
export declare const BEARER_HANDOFF_MAX_AGE_SECONDS = 60;
|
|
18
18
|
/** How long a bearer access token lives unless `bearer.accessTokenMaxAgeSeconds` says otherwise. */
|
|
19
19
|
export declare const RELYING_PARTY_DEFAULT_BEARER_ACCESS_TOKEN_MAX_AGE_SECONDS: number;
|
|
20
|
+
/** How long a spent refresh token may come back as a lost answer unless `bearer.refreshReuseGraceSeconds` says otherwise. */
|
|
21
|
+
export declare const RELYING_PARTY_DEFAULT_REFRESH_REUSE_GRACE_SECONDS = 60;
|
|
22
|
+
/** The longest `bearer.refreshReuseGraceSeconds`: a spent token that comes back later is always reuse. */
|
|
23
|
+
export declare const RELYING_PARTY_MAX_REFRESH_REUSE_GRACE_SECONDS = 300;
|
|
20
24
|
/**
|
|
21
25
|
* How long ending a session waits for the provider to take its tokens back.
|
|
22
26
|
* The local session is already revoked when that call runs.
|
|
@@ -62,6 +66,14 @@ export interface IRelyingPartySessionsOptions<TPrincipal extends object | undefi
|
|
|
62
66
|
session?: string;
|
|
63
67
|
intent?: string;
|
|
64
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* How the session and intent cookies go across sites: `{ sameSite: 'Lax' }`
|
|
71
|
+
* by default. A page framed on another site needs `sameSite: 'None'` (an
|
|
72
|
+
* https `publicOrigin` only), with `partitioned: true` where the browser
|
|
73
|
+
* keeps third-party cookies per top-level site. The constructor refuses
|
|
74
|
+
* every other combination.
|
|
75
|
+
*/
|
|
76
|
+
cookiePolicy?: IRelyingPartyCookiePolicy;
|
|
65
77
|
/** the prefix of the login routes; a login never returns into it */
|
|
66
78
|
loginPathPrefix?: string;
|
|
67
79
|
/**
|
|
@@ -78,13 +90,14 @@ export interface IRelyingPartySessionsOptions<TPrincipal extends object | undefi
|
|
|
78
90
|
* sign in through bearer hand-off and nothing else. The relying party never
|
|
79
91
|
* reads or sets a cookie — not even the clearing intent cookie of a callback
|
|
80
92
|
* that is no bearer login — so it has no CSRF token and takes no CSRF key:
|
|
81
|
-
* `csrfKey`, `csrfLabel` and `
|
|
93
|
+
* `csrfKey`, `csrfLabel`, `cookieNames` and `cookiePolicy` are refused, not
|
|
94
|
+
* ignored. The
|
|
82
95
|
* cookie steps (`openSession`, `startLogin`, `completeLogin`, `abandonLogin`,
|
|
83
96
|
* `finalizeLogin`, `clearSessionCookie`, `clearIntentCookie`) throw
|
|
84
97
|
* `RelyingPartyError('login_method_unavailable')` and `resolveCookieSession`
|
|
85
98
|
* answers `null`.
|
|
86
99
|
*/
|
|
87
|
-
export interface IRelyingPartyBearerOnlySessionsOptions<TPrincipal extends object | undefined = undefined> extends Omit<IRelyingPartySessionsOptions<TPrincipal>, 'provider' | 'csrfKey' | 'csrfLabel' | 'cookieNames' | 'cookieSessions' | 'bearer'> {
|
|
100
|
+
export interface IRelyingPartyBearerOnlySessionsOptions<TPrincipal extends object | undefined = undefined> extends Omit<IRelyingPartySessionsOptions<TPrincipal>, 'provider' | 'csrfKey' | 'csrfLabel' | 'cookieNames' | 'cookiePolicy' | 'cookieSessions' | 'bearer'> {
|
|
88
101
|
cookieSessions: false;
|
|
89
102
|
/** every bearer session comes from a live provider login, directly or through a hand-off opened from one */
|
|
90
103
|
provider: IOidcProvider;
|
|
@@ -92,6 +105,7 @@ export interface IRelyingPartyBearerOnlySessionsOptions<TPrincipal extends objec
|
|
|
92
105
|
csrfKey?: never;
|
|
93
106
|
csrfLabel?: never;
|
|
94
107
|
cookieNames?: never;
|
|
108
|
+
cookiePolicy?: never;
|
|
95
109
|
}
|
|
96
110
|
/**
|
|
97
111
|
* The relying-party session layer: provider logins through the authorization
|
|
@@ -120,6 +134,8 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
120
134
|
readonly secureCookies: boolean;
|
|
121
135
|
readonly sessionCookieName: string;
|
|
122
136
|
readonly intentCookieName: string;
|
|
137
|
+
/** how the session and intent cookies go across sites, as the constructor resolved `cookiePolicy` */
|
|
138
|
+
readonly cookiePolicy: Readonly<Required<IRelyingPartyCookiePolicy>>;
|
|
123
139
|
readonly loginPathPrefix: string;
|
|
124
140
|
readonly sessionMaxAgeSeconds: number;
|
|
125
141
|
constructor(optionsArg: IRelyingPartySessionsOptions<TPrincipal> | IRelyingPartyBearerOnlySessionsOptions<TPrincipal>);
|
|
@@ -181,6 +197,7 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
181
197
|
/**
|
|
182
198
|
* Ends every live session of a principal but `keepSessionId` (a password
|
|
183
199
|
* change keeps the session that asked for it) and answers how many ended.
|
|
200
|
+
* A session that expired is over already and is neither ended nor counted.
|
|
184
201
|
*/
|
|
185
202
|
endSessionsOfPrincipal(principalIdArg: string, optionsArg?: {
|
|
186
203
|
keepSessionId?: string;
|
|
@@ -308,15 +325,45 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
308
325
|
/**
|
|
309
326
|
* Rotates a bearer session's tokens: the refresh token is spent, a new
|
|
310
327
|
* access and refresh token answer, and the old access token stops working.
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
328
|
+
* A client serializes its refreshes, because a refresh token that comes
|
|
329
|
+
* back after it was spent ends the whole session, with one exception for
|
|
330
|
+
* an answer that never reached the client: within
|
|
331
|
+
* `bearer.refreshReuseGraceSeconds` of its rotation (60 by default), a
|
|
332
|
+
* spent refresh token whose successor was never presented — neither its
|
|
333
|
+
* access token nor its refresh token — revokes that successor and answers a
|
|
334
|
+
* new pair (`bearer_refresh_reissued`). Only hashes are stored, so the lost
|
|
335
|
+
* pair is replaced, never repeated. Once the successor was presented, after
|
|
336
|
+
* the window, or for a second retry that loses the race to the first, it is
|
|
337
|
+
* reuse. The provider login of a bearer login is checked on the way: a
|
|
338
|
+
* login idp.global ended ends the session here (`invalid_bearer_grant`), an
|
|
315
339
|
* unreachable provider fails with `AuthorityTokenError('authority_unavailable')`
|
|
316
340
|
* and spends nothing. A session `openBearerHandoff` opened has no provider
|
|
317
341
|
* login (no `idpSubject` is stored) and rotates without the provider.
|
|
318
342
|
*/
|
|
319
343
|
refreshBearerTokens(refreshTokenArg: unknown): Promise<IRelyingPartyBearerTokens>;
|
|
344
|
+
/**
|
|
345
|
+
* The successor of a spent generation when its answer may have been lost:
|
|
346
|
+
* the rotation is at most `refreshReuseGraceMs` old, and the successor is
|
|
347
|
+
* still current and was never presented. `null` otherwise, which is reuse.
|
|
348
|
+
*/
|
|
349
|
+
private lostSuccessorOf;
|
|
350
|
+
/**
|
|
351
|
+
* Issues a pair again for a spent generation whose answer was lost. The
|
|
352
|
+
* successor that answer carried is revoked first, by one conditional write
|
|
353
|
+
* that needs it current and unpresented: of two retries at once exactly one
|
|
354
|
+
* takes it, and the other is reuse, as is a successor presented in the
|
|
355
|
+
* meantime. Then the new generation is stored and the spent one names it,
|
|
356
|
+
* so a retry after this answer is lost too finds it within the same window
|
|
357
|
+
* (counted from the original rotation). A failure after the revocation
|
|
358
|
+
* leaves the session without a current generation; its retry is reuse.
|
|
359
|
+
*/
|
|
360
|
+
private reissueLostRotation;
|
|
361
|
+
/**
|
|
362
|
+
* Records the first presentation of a current generation's access or refresh
|
|
363
|
+
* token, once. Answers whether the generation is still current: `false`
|
|
364
|
+
* when a lost answer of its predecessor revoked it just now.
|
|
365
|
+
*/
|
|
366
|
+
private markBearerGenerationPresented;
|
|
320
367
|
/**
|
|
321
368
|
* The live session behind a bearer access token, or `null`: the token of the
|
|
322
369
|
* session's current generation, not expired, its session live and its
|
|
@@ -328,7 +375,9 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
328
375
|
/**
|
|
329
376
|
* Ends the session of a bearer token — a live access token or the current
|
|
330
377
|
* refresh token — like `endSession`. A refresh token that was already spent
|
|
331
|
-
* is reuse and ends the session as such
|
|
378
|
+
* is reuse and ends the session as such, unless `refreshBearerTokens` would
|
|
379
|
+
* take it as a lost answer (`lostSuccessorOf`): then it is a logout like the
|
|
380
|
+
* current one. Answers whether this call ended it.
|
|
332
381
|
*/
|
|
333
382
|
endBearerSession(tokenArg: unknown): Promise<boolean>;
|
|
334
383
|
/**
|
|
@@ -377,6 +426,8 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
377
426
|
*/
|
|
378
427
|
private openProviderLogin;
|
|
379
428
|
private newSessionDoc;
|
|
429
|
+
/** The attributes every session and intent cookie is set and cleared with: one policy for all of them. */
|
|
430
|
+
private cookieAttributes;
|
|
380
431
|
private csrfTokenOf;
|
|
381
432
|
private opening;
|
|
382
433
|
private snapshot;
|
|
@@ -396,7 +447,7 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
396
447
|
* `BEARER_HANDOFF_MAX_AGE_SECONDS` at most and never past the session.
|
|
397
448
|
*/
|
|
398
449
|
private storeBearerHandoff;
|
|
399
|
-
/** Stores the next token generation of a live session and answers its tokens;
|
|
450
|
+
/** Stores the next token generation of a live session and answers its tokens and its id; no token is stored in the clear. */
|
|
400
451
|
private issueBearerTokens;
|
|
401
452
|
/** A spent hand-off code or refresh token came back: whoever holds it, the session ends. */
|
|
402
453
|
private bearerCredentialReused;
|
|
@@ -470,9 +521,13 @@ export declare class RelyingPartySessions<TPrincipal extends object | undefined
|
|
|
470
521
|
* page per login start and per session the application opens. An ended
|
|
471
522
|
* session's expiry is its revocation at the latest, so the expiry index
|
|
472
523
|
* finds expired and revoked sessions alike. Each of them ended already: the
|
|
473
|
-
* row goes without an end, a hook or a provider call.
|
|
474
|
-
*
|
|
475
|
-
*
|
|
524
|
+
* row goes without an end, a hook or a provider call. Its children go
|
|
525
|
+
* first: in bearer mode its hand-offs and token generations, by their
|
|
526
|
+
* `sessionId` index, and only then the session row, which is the only link
|
|
527
|
+
* from a principal to them; a sweep that fails half way leaves the session
|
|
528
|
+
* row, and the next sweep finds it and deletes the rest. Expiry never moves
|
|
529
|
+
* later, so a session past the cutoff stays past it, and its row is deleted
|
|
530
|
+
* only while that still holds. A sweep that cannot run never blocks a
|
|
476
531
|
* sign-in.
|
|
477
532
|
*/
|
|
478
533
|
private sweepEndedSessions;
|