@atlasauth/pca-ciba 0.2.0 → 0.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/README.md +39 -3
- package/dist/client.d.ts +120 -0
- package/dist/client.js +330 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +72 -1
- package/dist/index.js +277 -28
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ const a = agent({
|
|
|
29
29
|
riskPolicy: { theta1: 0.3, theta2: 0.6 },
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
const review = reviewAction(a, 'stripe.payout', 'acct:1', { amount: 80 }, { goal: 'reconcile October refunds' });
|
|
32
|
+
const review = reviewAction(a, 'stripe.payout', 'acct:1', { amount: 80, currency: 'USD', payee: 'acct:supplier-9' }, { goal: 'reconcile October refunds' });
|
|
33
33
|
|
|
34
34
|
if (review.kind === 'step_up' && requiresCiba(review)) {
|
|
35
35
|
const broker = createCibaBroker({ onComplete: (session) => console.log(session.status) }); // omit onComplete for POLL
|
|
@@ -51,13 +51,49 @@ if (review.kind === 'step_up' && requiresCiba(review)) {
|
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
### Against a real OpenID Provider
|
|
55
|
+
|
|
56
|
+
`createCibaClient` talks to a provider's backchannel authentication and token endpoints (client authentication `client_secret_basic`) and implements the client side of POLL and PING:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { createCibaClient, verifyPingCallback } from '@atlasauth/pca-ciba';
|
|
60
|
+
|
|
61
|
+
const ciba = createCibaClient({
|
|
62
|
+
backchannelAuthenticationEndpoint: 'https://op.example/ciba/auth',
|
|
63
|
+
tokenEndpoint: 'https://op.example/token',
|
|
64
|
+
clientId: 'pca-agent',
|
|
65
|
+
clientSecret: process.env.CIBA_SECRET!,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const flow = await ciba.initiate(review.request, {
|
|
69
|
+
loginHint: 'owner@acme',
|
|
70
|
+
bindingMessage: { tokenOnly: true }, // for providers that restrict binding_message (see below)
|
|
71
|
+
stepUpScope: false, // for providers that only accept registered scopes
|
|
72
|
+
});
|
|
73
|
+
const result = await ciba.poller(flow).wait(); // 'approved' (with tokens) | 'denied' | 'expired'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The poller never polls faster than the provider's `interval`, adds 5 seconds on every `slow_down` (CIBA Core 11), stops at `expires_in`, and never re-sends a settled `auth_req_id`. For PING delivery pass `delivery: 'ping'`, check the provider's callback with `verifyPingCallback`, then call `poller.notify()` (which also wakes a `poll()`/`wait()` that is sleeping) and `poll()`. Concurrent `poll()` calls share one token request; thrown fetches, 5xx replies and non-JSON replies back the next poll off (the error has `retryable: true`, and `wait()` retries up to five in a row); every request has a timeout (`timeoutMs`, default 30 s) and `wait({ signal })` / `poll({ signal })` cancel the in-flight fetch. Endpoints must be `https://`; `allowInsecureHttp: true` exists for a local test provider only. A caller-supplied `clientNotificationToken` must be at least 22 characters (128 bits). The returned tokens are the provider's response and are not verified by this package.
|
|
77
|
+
|
|
78
|
+
The message is rendered ONLY from a canonical structured action (`cibaActionFromStepUp`) in a fixed order, `Approve <verb> <amount> <CUR> to "<payee>" on <resource>` (tokenOnly: `Approve-<verb>-<amount>-<CUR>-to-<payee>-<resource>`), and fails loud rather than misstating the action (R3-05, breaking). `params` may hold only `amount` (number or plain decimal string), `currency` (3 letters, REQUIRED next to an amount and always shown; there is no `$` shorthand or USD default) and one payee field (`payee`, `to`, `recipient`, `beneficiary` or `destination`; REQUIRED next to an amount). Every other `params` key makes `toCibaAuthRequest` throw, so a hidden `amt`, `total` or `memo` can never ride along unseen. The payee is shown in full inside double quotes (at most 64 characters; control, bidirectional and invisible characters, quotes, backslashes and a "because you asked" clause are refused, not altered; tokenOnly needs an ASCII payee). The verb and resource are plain identifiers (`[A-Za-z0-9][A-Za-z0-9._:/#@+-]{0,63}`), never free text. With `bindingMessage.maxChars`, only the optional goal clause shrinks, and if the head alone does not fit it throws. Not covered: look-alike (homoglyph) characters inside an otherwise printable payee.
|
|
79
|
+
|
|
80
|
+
Provider limits to know about: Keycloak accepts a `binding_message` of at most 50 characters from a narrow ASCII set without spaces, so the default rich message is refused with `invalid_binding_message` there; use `bindingMessage: { tokenOnly: true }`. In that mode the message is all-or-nothing: the amount must be a plain non-negative decimal (no sign or exponent), the currency a 3-letter code, and if `maxChars` cannot hold the verb, amount, currency and resource in full, `toCibaAuthRequest` throws rather than sending a shortened message. A provider that does not know the per-verb scope `urn:atlas:pca:stepup:<verb>` answers `invalid_scope`; pass `stepUpScope: false`.
|
|
81
|
+
|
|
54
82
|
`toCibaAuthRequest(stepUp, opts?)` is the pure mapping from a step-up to a CIBA request, if you want to drive your own broker or a real OpenID provider.
|
|
55
83
|
|
|
56
84
|
## Status
|
|
57
85
|
|
|
58
|
-
The broker is in-memory and models the CIBA lifecycle without any network; a production deployment would swap in a real OpenID provider. The package computes approval envelopes and the derived trust budget and authorises nothing on its own: `cibaDecisionToCosign` is only the budget-level effect. The cryptographic cosign (FROST) is produced and verified separately, and the resource server's verifier remains the authority. Cryptography in PCA is unaudited.
|
|
86
|
+
Experimental. The broker is in-memory and models the CIBA lifecycle without any network; a production deployment would swap in a real OpenID provider. The package computes approval envelopes and the derived trust budget and authorises nothing on its own: `cibaDecisionToCosign` is only the budget-level effect. The cryptographic cosign (FROST) is produced and verified separately, and the resource server's verifier remains the authority. Cryptography in PCA is unaudited.
|
|
87
|
+
|
|
88
|
+
The human decision is **unauthenticated data**. `resolve` and `cibaDecisionToCosign` take the decision string as given: the client does not verify the ID token, and the approval recharges the trust budget generically without being cryptographically bound to the action the human was shown. Do not treat a CIBA approval as an authorisation of a specific action; only the verified cosign (a signature over `thresholdMessage` of that PCActn) is. Verify the provider's ID token yourself, and bind the `binding_message` to the action digest, before you let a decision recharge a budget.
|
|
89
|
+
|
|
90
|
+
What has been checked against OpenID Connect CIBA Core 1.0 (Final): the specification's own examples (committed with source URL and sha256) are replayed through the independent `openid-client` library (6.8.2), which also drives the broker end to end through a small HTTP provider written for the tests (initiate, poll through `authorization_pending`, approve, deny, expiry). The values the package emits are asserted against the specification's requirements: `auth_req_id` is unguessable (160 random bits, restricted character set), `requested_expiry` is a positive integer, `scope` carries `openid` and only valid scope-token characters, and `binding_message` is a single short line of plain text.
|
|
91
|
+
|
|
92
|
+
Validated against a real provider: Keycloak 26.8.0 (official release distribution on OpenJDK 21, CIBA enabled, a mock authentication-channel device playing the human). Ten end-to-end checks run POLL approve, deny (cancelled and unauthorized), expiry (including a late approval that the provider refuses), PING delivery with a notification-token callback, `login_hint` by username, e-mail and different case, unknown-user, bad-secret, bad-scope, `user_code` and malformed `requested_expiry` errors, `slow_down` enforcement (an early poll is answered `slow_down`; the client backs off by 5 seconds), single-use of an approved `auth_req_id`, and the `binding_message` and scope limits above. The real request and response transcripts (tokens and credentials redacted) are committed as a fixture and replayed offline on every run. The live run is gated behind `PCA_CIBA_KEYCLOAK_URL`, and the repository's `scripts/run-keycloak-ciba.sh` reproduces it end to end and tears the provider down.
|
|
93
|
+
|
|
94
|
+
Observed provider behaviour that differs from the specification: Keycloak does not honour `requested_expiry` (it returns its own `expires_in`), does not require `openid` in `scope`, reports an unknown user as `invalid_request` with description `invalid_user` rather than `unknown_user_id`, reports a bad client secret as `unauthorized_client`, and its stock user resolver supports `login_hint` only (`login_hint_token` and `id_token_hint` are refused with `invalid_user` unless a custom resolver is installed).
|
|
59
95
|
|
|
60
|
-
|
|
96
|
+
Not validated: other providers (Auth0, Descope, Stytch and others were not tried), PUSH mode, signed authentication requests, `user_code`, `login_hint_token` and `id_token_hint` against a provider that supports them, and the in-memory broker's own token-endpoint behaviour against any real client. The in-memory broker remains a test double.
|
|
61
97
|
|
|
62
98
|
## License
|
|
63
99
|
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A network client for a real OpenID Provider's CIBA endpoints (OpenID CIBA Core 1.0): start a
|
|
3
|
+
* backchannel authentication request and wait for the human's decision by POLL or PING. It is the
|
|
4
|
+
* relying-party side that `createCibaBroker` (in-memory, test-double) models.
|
|
5
|
+
*
|
|
6
|
+
* Poll discipline follows CIBA Core 7.3 / 11: the client never polls faster than the `interval` the OP
|
|
7
|
+
* returned, adds at least 5 seconds to it on every `slow_down`, and stops at `expires_in`. A terminal
|
|
8
|
+
* answer (approved / denied / expired) is cached, so a settled flow is never re-sent to the token
|
|
9
|
+
* endpoint (an approved `auth_req_id` is single-use at real providers).
|
|
10
|
+
*
|
|
11
|
+
* The client authenticates with `client_secret_basic`. The returned tokens are the OP's response, not
|
|
12
|
+
* verified here: a caller that relies on the ID token must verify it with its own JOSE library.
|
|
13
|
+
*/
|
|
14
|
+
import { type CibaAuthRequest, type CibaRequestOptions } from './index';
|
|
15
|
+
import type { StepUpRequest } from '@atlasauth/pca';
|
|
16
|
+
export type CibaDelivery = 'poll' | 'ping';
|
|
17
|
+
/** An error response from the OP (RFC 6749 5.2 / CIBA Core 13), or a malformed reply. */
|
|
18
|
+
export declare class CibaProviderError extends Error {
|
|
19
|
+
readonly error: string;
|
|
20
|
+
readonly errorDescription: string | undefined;
|
|
21
|
+
readonly status: number;
|
|
22
|
+
/** True for failures worth retrying (network error, timeout, 5xx, non-JSON reply); not for a definitive OP answer. */
|
|
23
|
+
readonly retryable: boolean;
|
|
24
|
+
constructor(status: number, error: string, errorDescription?: string, retryable?: boolean);
|
|
25
|
+
}
|
|
26
|
+
export interface CibaClientConfig {
|
|
27
|
+
backchannelAuthenticationEndpoint: string;
|
|
28
|
+
tokenEndpoint: string;
|
|
29
|
+
clientId: string;
|
|
30
|
+
clientSecret: string;
|
|
31
|
+
/** Injectable for tests. Default global `fetch`. */
|
|
32
|
+
fetch?: typeof fetch;
|
|
33
|
+
/** Injectable for tests. Default `setTimeout`. */
|
|
34
|
+
sleep?: (ms: number) => Promise<void>;
|
|
35
|
+
/** Clock in ms. Default `Date.now`. */
|
|
36
|
+
now?: () => number;
|
|
37
|
+
/** Per-request timeout in ms for every call to the OP. Default 30000. */
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Permit `http://` endpoints. The client secret and the `auth_req_id` travel on these requests, so this
|
|
41
|
+
* is for local test providers only. Default false: a non-https endpoint is rejected.
|
|
42
|
+
*/
|
|
43
|
+
allowInsecureHttp?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface CibaInitiateOptions extends CibaRequestOptions {
|
|
46
|
+
/** Exactly one identifying hint is allowed (CIBA Core 7.1). `loginHint` comes from {@link CibaRequestOptions}. */
|
|
47
|
+
loginHintToken?: string;
|
|
48
|
+
idTokenHint?: string;
|
|
49
|
+
/** `ping` sends a `client_notification_token` (generated if not given); `poll` (default) sends none. */
|
|
50
|
+
delivery?: CibaDelivery;
|
|
51
|
+
clientNotificationToken?: string;
|
|
52
|
+
acrValues?: string;
|
|
53
|
+
userCode?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface CibaFlow {
|
|
56
|
+
/** The OP-issued `auth_req_id`. */
|
|
57
|
+
authReqId: string;
|
|
58
|
+
expiresInSec: number;
|
|
59
|
+
/** Interval the OP asked for, in seconds. */
|
|
60
|
+
intervalSec: number;
|
|
61
|
+
/** ms epoch the OP answered. */
|
|
62
|
+
startedAt: number;
|
|
63
|
+
delivery: CibaDelivery;
|
|
64
|
+
clientNotificationToken?: string;
|
|
65
|
+
/** The request PCA derived (scope, binding message, ...) that was sent. */
|
|
66
|
+
request: CibaAuthRequest;
|
|
67
|
+
}
|
|
68
|
+
export interface CibaTokenResponse {
|
|
69
|
+
access_token: string;
|
|
70
|
+
token_type: string;
|
|
71
|
+
expires_in?: number;
|
|
72
|
+
id_token?: string;
|
|
73
|
+
refresh_token?: string;
|
|
74
|
+
scope?: string;
|
|
75
|
+
}
|
|
76
|
+
export type CibaPollResult = {
|
|
77
|
+
status: 'pending';
|
|
78
|
+
intervalSec: number;
|
|
79
|
+
} | {
|
|
80
|
+
status: 'approved';
|
|
81
|
+
tokens: CibaTokenResponse;
|
|
82
|
+
} | {
|
|
83
|
+
status: 'denied';
|
|
84
|
+
error: string;
|
|
85
|
+
} | {
|
|
86
|
+
status: 'expired';
|
|
87
|
+
};
|
|
88
|
+
export interface CibaPoller {
|
|
89
|
+
/** Current poll interval in seconds (grows on `slow_down`). */
|
|
90
|
+
intervalSec(): number;
|
|
91
|
+
/** Sleep until the interval allows it, then ask the token endpoint once. */
|
|
92
|
+
poll(opts?: {
|
|
93
|
+
signal?: AbortSignal;
|
|
94
|
+
}): Promise<CibaPollResult>;
|
|
95
|
+
/** Poll until the flow settles; honours `signal`. */
|
|
96
|
+
wait(opts?: {
|
|
97
|
+
signal?: AbortSignal;
|
|
98
|
+
}): Promise<Exclude<CibaPollResult, {
|
|
99
|
+
status: 'pending';
|
|
100
|
+
}>>;
|
|
101
|
+
/** A PING arrived: the next `poll()` may go out immediately, and a `poll()`/`wait()` that is sleeping wakes now. */
|
|
102
|
+
notify(): void;
|
|
103
|
+
}
|
|
104
|
+
export interface CibaClient {
|
|
105
|
+
initiate(stepUp: StepUpRequest, opts?: CibaInitiateOptions): Promise<CibaFlow>;
|
|
106
|
+
poller(flow: CibaFlow): CibaPoller;
|
|
107
|
+
}
|
|
108
|
+
/** A fresh `client_notification_token` (CIBA Core 7.1: at least 128 bits of entropy, at most 1024 chars). */
|
|
109
|
+
export declare function newClientNotificationToken(): string;
|
|
110
|
+
export declare function createCibaClient(cfg: CibaClientConfig): CibaClient;
|
|
111
|
+
/**
|
|
112
|
+
* Validate a PING callback (CIBA Core 10.2): `Authorization: Bearer <client_notification_token>` and a JSON
|
|
113
|
+
* body `{ "auth_req_id": ... }`. Returns the `auth_req_id` only when the bearer matches the token sent for
|
|
114
|
+
* that flow (constant-time comparison); throws otherwise. The callback carries no decision: call
|
|
115
|
+
* `poller.notify()` and then `poll()` to fetch it.
|
|
116
|
+
*/
|
|
117
|
+
export declare function verifyPingCallback(input: {
|
|
118
|
+
authorization: string | undefined;
|
|
119
|
+
body: unknown;
|
|
120
|
+
}, flow: Pick<CibaFlow, 'authReqId' | 'clientNotificationToken'>): string;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* A network client for a real OpenID Provider's CIBA endpoints (OpenID CIBA Core 1.0): start a
|
|
4
|
+
* backchannel authentication request and wait for the human's decision by POLL or PING. It is the
|
|
5
|
+
* relying-party side that `createCibaBroker` (in-memory, test-double) models.
|
|
6
|
+
*
|
|
7
|
+
* Poll discipline follows CIBA Core 7.3 / 11: the client never polls faster than the `interval` the OP
|
|
8
|
+
* returned, adds at least 5 seconds to it on every `slow_down`, and stops at `expires_in`. A terminal
|
|
9
|
+
* answer (approved / denied / expired) is cached, so a settled flow is never re-sent to the token
|
|
10
|
+
* endpoint (an approved `auth_req_id` is single-use at real providers).
|
|
11
|
+
*
|
|
12
|
+
* The client authenticates with `client_secret_basic`. The returned tokens are the OP's response, not
|
|
13
|
+
* verified here: a caller that relies on the ID token must verify it with its own JOSE library.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.CibaProviderError = void 0;
|
|
17
|
+
exports.newClientNotificationToken = newClientNotificationToken;
|
|
18
|
+
exports.createCibaClient = createCibaClient;
|
|
19
|
+
exports.verifyPingCallback = verifyPingCallback;
|
|
20
|
+
const node_crypto_1 = require("node:crypto");
|
|
21
|
+
const index_1 = require("./index");
|
|
22
|
+
const CIBA_GRANT = 'urn:openid:params:grant-type:ciba';
|
|
23
|
+
/** CIBA Core 11: on `slow_down` the interval grows by at least 5 seconds. */
|
|
24
|
+
const SLOW_DOWN_STEP_SEC = 5;
|
|
25
|
+
/** An error response from the OP (RFC 6749 5.2 / CIBA Core 13), or a malformed reply. */
|
|
26
|
+
class CibaProviderError extends Error {
|
|
27
|
+
error;
|
|
28
|
+
errorDescription;
|
|
29
|
+
status;
|
|
30
|
+
/** True for failures worth retrying (network error, timeout, 5xx, non-JSON reply); not for a definitive OP answer. */
|
|
31
|
+
retryable;
|
|
32
|
+
constructor(status, error, errorDescription, retryable = false) {
|
|
33
|
+
super(`ciba: provider returned ${String(status)} ${error}${errorDescription !== undefined ? ` (${errorDescription})` : ''}`);
|
|
34
|
+
this.name = 'CibaProviderError';
|
|
35
|
+
this.status = status;
|
|
36
|
+
this.error = error;
|
|
37
|
+
this.errorDescription = errorDescription;
|
|
38
|
+
this.retryable = retryable;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.CibaProviderError = CibaProviderError;
|
|
42
|
+
async function readJson(res) {
|
|
43
|
+
const text = await res.text();
|
|
44
|
+
let parsed;
|
|
45
|
+
try {
|
|
46
|
+
parsed = JSON.parse(text);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
throw new CibaProviderError(res.status, 'invalid_response', 'the provider reply was not JSON', true);
|
|
50
|
+
}
|
|
51
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
52
|
+
throw new CibaProviderError(res.status, 'invalid_response', 'the provider reply was not a JSON object');
|
|
53
|
+
}
|
|
54
|
+
return parsed;
|
|
55
|
+
}
|
|
56
|
+
function providerError(status, body) {
|
|
57
|
+
const error = typeof body['error'] === 'string' ? body['error'] : 'invalid_response';
|
|
58
|
+
const desc = typeof body['error_description'] === 'string' ? body['error_description'] : undefined;
|
|
59
|
+
return new CibaProviderError(status, error, desc);
|
|
60
|
+
}
|
|
61
|
+
function positiveInt(value, name, status) {
|
|
62
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) {
|
|
63
|
+
throw new CibaProviderError(status, 'invalid_response', `${name} must be a positive integer`);
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
const MIN_NOTIFICATION_TOKEN_CHARS = 22; // 22 base64url chars = 132 bits
|
|
68
|
+
const MAX_NOTIFICATION_TOKEN_CHARS = 1024;
|
|
69
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
70
|
+
const MAX_BACKOFF_MS = 60_000;
|
|
71
|
+
const MAX_CONSECUTIVE_TRANSIENT = 5;
|
|
72
|
+
function checkEndpoint(name, value, allowInsecure) {
|
|
73
|
+
let u;
|
|
74
|
+
try {
|
|
75
|
+
u = new URL(value);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new RangeError(`ciba: ${name} is not a valid URL`);
|
|
79
|
+
}
|
|
80
|
+
if (u.protocol === 'https:')
|
|
81
|
+
return;
|
|
82
|
+
if (u.protocol === 'http:' && allowInsecure)
|
|
83
|
+
return;
|
|
84
|
+
throw new RangeError(`ciba: ${name} must be an https:// URL (set allowInsecureHttp only for a local test provider)`);
|
|
85
|
+
}
|
|
86
|
+
/** A fresh `client_notification_token` (CIBA Core 7.1: at least 128 bits of entropy, at most 1024 chars). */
|
|
87
|
+
function newClientNotificationToken() {
|
|
88
|
+
return (0, node_crypto_1.randomBytes)(32).toString('base64url');
|
|
89
|
+
}
|
|
90
|
+
function createCibaClient(cfg) {
|
|
91
|
+
const doFetch = cfg.fetch ?? fetch;
|
|
92
|
+
const clock = cfg.now ?? Date.now;
|
|
93
|
+
const timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
94
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
95
|
+
throw new RangeError('ciba: timeoutMs must be a positive number');
|
|
96
|
+
checkEndpoint('backchannelAuthenticationEndpoint', cfg.backchannelAuthenticationEndpoint, cfg.allowInsecureHttp === true);
|
|
97
|
+
checkEndpoint('tokenEndpoint', cfg.tokenEndpoint, cfg.allowInsecureHttp === true);
|
|
98
|
+
const basic = `Basic ${Buffer.from(`${encodeURIComponent(cfg.clientId)}:${encodeURIComponent(cfg.clientSecret)}`).toString('base64')}`;
|
|
99
|
+
/** One request with a hard timeout; the caller's signal also cancels the fetch itself. */
|
|
100
|
+
async function post(url, form, signal) {
|
|
101
|
+
if (signal?.aborted === true)
|
|
102
|
+
throw new Error('ciba: wait aborted');
|
|
103
|
+
const ac = new AbortController();
|
|
104
|
+
const timer = setTimeout(() => ac.abort(new Error('timeout')), timeoutMs);
|
|
105
|
+
const onAbort = () => ac.abort(new Error('aborted'));
|
|
106
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
107
|
+
try {
|
|
108
|
+
return await doFetch(url, {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: { authorization: basic, 'content-type': 'application/x-www-form-urlencoded', accept: 'application/json' },
|
|
111
|
+
body: form.toString(),
|
|
112
|
+
signal: ac.signal,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
if (signal !== undefined && signal.aborted)
|
|
117
|
+
throw new Error('ciba: wait aborted');
|
|
118
|
+
throw new CibaProviderError(0, 'network_error', e instanceof Error ? e.message : 'request failed', true);
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
clearTimeout(timer);
|
|
122
|
+
signal?.removeEventListener('abort', onAbort);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
async initiate(stepUp, opts = {}) {
|
|
127
|
+
const hints = [opts.loginHint, opts.loginHintToken, opts.idTokenHint].filter((h) => h !== undefined);
|
|
128
|
+
if (hints.length !== 1) {
|
|
129
|
+
throw new RangeError('ciba: exactly one of loginHint, loginHintToken, idTokenHint is required (CIBA Core 7.1)');
|
|
130
|
+
}
|
|
131
|
+
const delivery = opts.delivery ?? 'poll';
|
|
132
|
+
const notificationToken = delivery === 'ping' ? (opts.clientNotificationToken ?? newClientNotificationToken()) : undefined;
|
|
133
|
+
if (opts.clientNotificationToken !== undefined &&
|
|
134
|
+
(opts.clientNotificationToken.length < MIN_NOTIFICATION_TOKEN_CHARS ||
|
|
135
|
+
opts.clientNotificationToken.length > MAX_NOTIFICATION_TOKEN_CHARS ||
|
|
136
|
+
!/^[\x21-\x7E]+$/.test(opts.clientNotificationToken))) {
|
|
137
|
+
throw new RangeError(`ciba: clientNotificationToken must be ${String(MIN_NOTIFICATION_TOKEN_CHARS)}..${String(MAX_NOTIFICATION_TOKEN_CHARS)} printable characters (>= 128 bits, CIBA Core 7.1)`);
|
|
138
|
+
}
|
|
139
|
+
const request = (0, index_1.toCibaAuthRequest)(stepUp, opts);
|
|
140
|
+
const form = new URLSearchParams({
|
|
141
|
+
scope: request.scope,
|
|
142
|
+
binding_message: request.binding_message,
|
|
143
|
+
requested_expiry: String(request.requested_expiry),
|
|
144
|
+
});
|
|
145
|
+
if (opts.loginHint !== undefined)
|
|
146
|
+
form.set('login_hint', opts.loginHint);
|
|
147
|
+
if (opts.loginHintToken !== undefined)
|
|
148
|
+
form.set('login_hint_token', opts.loginHintToken);
|
|
149
|
+
if (opts.idTokenHint !== undefined)
|
|
150
|
+
form.set('id_token_hint', opts.idTokenHint);
|
|
151
|
+
if (opts.acrValues !== undefined)
|
|
152
|
+
form.set('acr_values', opts.acrValues);
|
|
153
|
+
if (opts.userCode !== undefined)
|
|
154
|
+
form.set('user_code', opts.userCode);
|
|
155
|
+
if (notificationToken !== undefined)
|
|
156
|
+
form.set('client_notification_token', notificationToken);
|
|
157
|
+
const res = await post(cfg.backchannelAuthenticationEndpoint, form);
|
|
158
|
+
const body = await readJson(res);
|
|
159
|
+
if (!res.ok)
|
|
160
|
+
throw providerError(res.status, body);
|
|
161
|
+
const authReqId = body['auth_req_id'];
|
|
162
|
+
if (typeof authReqId !== 'string' || authReqId.length === 0) {
|
|
163
|
+
throw new CibaProviderError(res.status, 'invalid_response', 'auth_req_id missing');
|
|
164
|
+
}
|
|
165
|
+
const expiresInSec = positiveInt(body['expires_in'], 'expires_in', res.status);
|
|
166
|
+
// CIBA Core 7.3: `interval` is optional and defaults to 5 seconds.
|
|
167
|
+
const intervalSec = body['interval'] === undefined ? 5 : positiveInt(body['interval'], 'interval', res.status);
|
|
168
|
+
return {
|
|
169
|
+
authReqId,
|
|
170
|
+
expiresInSec,
|
|
171
|
+
intervalSec,
|
|
172
|
+
startedAt: clock(),
|
|
173
|
+
delivery,
|
|
174
|
+
...(notificationToken !== undefined ? { clientNotificationToken: notificationToken } : {}),
|
|
175
|
+
request,
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
poller(flow) {
|
|
179
|
+
let intervalMs = flow.intervalSec * 1000;
|
|
180
|
+
let nextAt = flow.startedAt + intervalMs;
|
|
181
|
+
const deadline = flow.startedAt + flow.expiresInSec * 1000;
|
|
182
|
+
let settled;
|
|
183
|
+
let inflight;
|
|
184
|
+
let wake;
|
|
185
|
+
let failures = 0;
|
|
186
|
+
/** Sleep `ms`, ending early on notify() or on the caller's abort. */
|
|
187
|
+
async function pause(ms, signal) {
|
|
188
|
+
let timer;
|
|
189
|
+
let onAbort;
|
|
190
|
+
const racers = [
|
|
191
|
+
cfg.sleep !== undefined ? cfg.sleep(ms) : new Promise((r) => { timer = setTimeout(r, ms); }),
|
|
192
|
+
new Promise((r) => { wake = r; }),
|
|
193
|
+
];
|
|
194
|
+
if (signal !== undefined) {
|
|
195
|
+
racers.push(new Promise((r) => { onAbort = () => r(); signal.addEventListener('abort', onAbort, { once: true }); }));
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
await Promise.race(racers);
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
wake = undefined;
|
|
202
|
+
if (timer !== undefined)
|
|
203
|
+
clearTimeout(timer);
|
|
204
|
+
if (signal !== undefined && onAbort !== undefined)
|
|
205
|
+
signal.removeEventListener('abort', onAbort);
|
|
206
|
+
}
|
|
207
|
+
if (signal?.aborted === true)
|
|
208
|
+
throw new Error('ciba: wait aborted');
|
|
209
|
+
}
|
|
210
|
+
function backoff() {
|
|
211
|
+
failures += 1;
|
|
212
|
+
const delay = Math.min(MAX_BACKOFF_MS, intervalMs * 2 ** Math.min(failures, 6));
|
|
213
|
+
nextAt = clock() + delay;
|
|
214
|
+
}
|
|
215
|
+
async function doPoll(signal) {
|
|
216
|
+
if (settled !== undefined)
|
|
217
|
+
return settled;
|
|
218
|
+
const wait = nextAt - clock();
|
|
219
|
+
if (wait > 0)
|
|
220
|
+
await pause(wait, signal);
|
|
221
|
+
if (settled !== undefined)
|
|
222
|
+
return settled;
|
|
223
|
+
if (clock() >= deadline) {
|
|
224
|
+
settled = { status: 'expired' };
|
|
225
|
+
return settled;
|
|
226
|
+
}
|
|
227
|
+
let res;
|
|
228
|
+
let body;
|
|
229
|
+
try {
|
|
230
|
+
res = await post(cfg.tokenEndpoint, new URLSearchParams({ grant_type: CIBA_GRANT, auth_req_id: flow.authReqId }), signal);
|
|
231
|
+
if (res.status >= 500) {
|
|
232
|
+
await res.text().catch(() => '');
|
|
233
|
+
throw new CibaProviderError(res.status, 'server_error', 'the provider answered with a server error', true);
|
|
234
|
+
}
|
|
235
|
+
body = await readJson(res);
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
if (e instanceof CibaProviderError && e.retryable)
|
|
239
|
+
backoff();
|
|
240
|
+
throw e;
|
|
241
|
+
}
|
|
242
|
+
failures = 0;
|
|
243
|
+
nextAt = clock() + intervalMs;
|
|
244
|
+
if (res.ok) {
|
|
245
|
+
const at = body['access_token'];
|
|
246
|
+
const tt = body['token_type'];
|
|
247
|
+
if (typeof at !== 'string' || typeof tt !== 'string') {
|
|
248
|
+
throw new CibaProviderError(res.status, 'invalid_response', 'token response lacks access_token / token_type');
|
|
249
|
+
}
|
|
250
|
+
settled = { status: 'approved', tokens: body };
|
|
251
|
+
return settled;
|
|
252
|
+
}
|
|
253
|
+
const err = providerError(res.status, body);
|
|
254
|
+
switch (err.error) {
|
|
255
|
+
case 'authorization_pending':
|
|
256
|
+
return { status: 'pending', intervalSec: intervalMs / 1000 };
|
|
257
|
+
case 'slow_down':
|
|
258
|
+
intervalMs += SLOW_DOWN_STEP_SEC * 1000;
|
|
259
|
+
nextAt = clock() + intervalMs;
|
|
260
|
+
return { status: 'pending', intervalSec: intervalMs / 1000 };
|
|
261
|
+
case 'access_denied':
|
|
262
|
+
settled = { status: 'denied', error: err.error };
|
|
263
|
+
return settled;
|
|
264
|
+
case 'expired_token':
|
|
265
|
+
settled = { status: 'expired' };
|
|
266
|
+
return settled;
|
|
267
|
+
default:
|
|
268
|
+
throw err;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const poller = {
|
|
272
|
+
intervalSec: () => intervalMs / 1000,
|
|
273
|
+
notify() {
|
|
274
|
+
nextAt = clock();
|
|
275
|
+
wake?.();
|
|
276
|
+
},
|
|
277
|
+
// Concurrent callers share one in-flight request: an approved auth_req_id is single-use at real OPs.
|
|
278
|
+
poll(opts = {}) {
|
|
279
|
+
if (inflight !== undefined)
|
|
280
|
+
return inflight;
|
|
281
|
+
const p = doPoll(opts.signal).finally(() => {
|
|
282
|
+
inflight = undefined;
|
|
283
|
+
});
|
|
284
|
+
inflight = p;
|
|
285
|
+
return p;
|
|
286
|
+
},
|
|
287
|
+
async wait(opts = {}) {
|
|
288
|
+
let transient = 0;
|
|
289
|
+
for (;;) {
|
|
290
|
+
if (opts.signal?.aborted === true)
|
|
291
|
+
throw new Error('ciba: wait aborted');
|
|
292
|
+
try {
|
|
293
|
+
const r = await poller.poll(opts.signal !== undefined ? { signal: opts.signal } : {});
|
|
294
|
+
transient = 0;
|
|
295
|
+
if (r.status !== 'pending')
|
|
296
|
+
return r;
|
|
297
|
+
}
|
|
298
|
+
catch (e) {
|
|
299
|
+
if (!(e instanceof CibaProviderError) || !e.retryable || ++transient >= MAX_CONSECUTIVE_TRANSIENT)
|
|
300
|
+
throw e;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
return poller;
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Validate a PING callback (CIBA Core 10.2): `Authorization: Bearer <client_notification_token>` and a JSON
|
|
311
|
+
* body `{ "auth_req_id": ... }`. Returns the `auth_req_id` only when the bearer matches the token sent for
|
|
312
|
+
* that flow (constant-time comparison); throws otherwise. The callback carries no decision: call
|
|
313
|
+
* `poller.notify()` and then `poll()` to fetch it.
|
|
314
|
+
*/
|
|
315
|
+
function verifyPingCallback(input, flow) {
|
|
316
|
+
if (flow.clientNotificationToken === undefined)
|
|
317
|
+
throw new Error('ciba: flow was not started in ping mode');
|
|
318
|
+
const m = /^bearer +(\S+)$/i.exec(input.authorization ?? '');
|
|
319
|
+
if (m === null)
|
|
320
|
+
throw new Error('ciba: ping callback lacks a bearer token');
|
|
321
|
+
const digest = (v) => (0, node_crypto_1.createHash)('sha256').update(v).digest();
|
|
322
|
+
if (!(0, node_crypto_1.timingSafeEqual)(digest(m[1]), digest(flow.clientNotificationToken))) {
|
|
323
|
+
throw new Error('ciba: ping callback bearer does not match the client_notification_token');
|
|
324
|
+
}
|
|
325
|
+
const id = typeof input.body === 'object' && input.body !== null ? input.body['auth_req_id'] : undefined;
|
|
326
|
+
if (typeof id !== 'string' || id !== flow.authReqId)
|
|
327
|
+
throw new Error('ciba: ping callback auth_req_id does not match this flow');
|
|
328
|
+
return id;
|
|
329
|
+
}
|
|
330
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -53,16 +53,66 @@ export interface CibaAuthRequest {
|
|
|
53
53
|
}
|
|
54
54
|
/** Options shared by `toCibaAuthRequest` and the broker's `start`. */
|
|
55
55
|
export interface CibaRequestOptions {
|
|
56
|
-
/** Override the `requested_expiry` (seconds). Default 300. */
|
|
56
|
+
/** Override the `requested_expiry` (seconds). Must be a positive integer (CIBA Core 7.1). Default 300. */
|
|
57
57
|
expiresInSec?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Use this `auth_req_id` instead of the deterministic derivation. CIBA Core 7.3 requires an
|
|
60
|
+
* `auth_req_id` to carry at least 128 bits of entropy and use only `A-Za-z0-9.-_`; the default
|
|
61
|
+
* derivation hashes PUBLIC step-up fields and is therefore NOT secret. {@link createCibaBroker}
|
|
62
|
+
* always supplies a fresh random value here.
|
|
63
|
+
*/
|
|
64
|
+
authReqId?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Include the per-verb step-up scope `urn:atlas:pca:stepup:<verb>` next to `openid`. Default `true`.
|
|
67
|
+
* Real providers reject scopes that are not registered for the client (Keycloak answers `invalid_scope`),
|
|
68
|
+
* and per-verb scopes are open-ended, so set `false` when the OP has no such scope; the verb is then
|
|
69
|
+
* carried by the `binding_message` alone.
|
|
70
|
+
*/
|
|
71
|
+
stepUpScope?: boolean;
|
|
58
72
|
/** CIBA `login_hint` for the OP: the identifier of the human to notify. */
|
|
59
73
|
loginHint?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Constrain the `binding_message` for providers that restrict it. CIBA Core 7.1 only says the message
|
|
76
|
+
* SHOULD be short and plain text; real providers enforce more (Keycloak 26.8 accepts at most 50
|
|
77
|
+
* characters from a narrow ASCII set and rejects spaces, `$`, `:`, `,`, `(`, `)` and `@` with
|
|
78
|
+
* `invalid_binding_message`). With `tokenOnly` the message is rendered as hyphen-joined tokens using only
|
|
79
|
+
* `A-Za-z0-9._-` (for example `Approve-stripe.payout-80-USD-acct-1`), cut at `maxChars` on a token
|
|
80
|
+
* boundary. Default: the rich one-line form, unchanged.
|
|
81
|
+
*/
|
|
82
|
+
bindingMessage?: {
|
|
83
|
+
maxChars?: number;
|
|
84
|
+
tokenOnly?: boolean;
|
|
85
|
+
};
|
|
86
|
+
/** CIBA `interval` (seconds, positive integer): minimum poll spacing the OP/broker enforces. Default 5. */
|
|
87
|
+
interval?: number;
|
|
60
88
|
/**
|
|
61
89
|
* The agent's human-facing name used in the binding message ("because you asked <actsFor> to …"),
|
|
62
90
|
* e.g. `"support-bot"`. Default `"your agent"`.
|
|
63
91
|
*/
|
|
64
92
|
actsFor?: string;
|
|
65
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* R3-05: the approval message is rendered ONLY from this canonical, fixed-order structure. Anything in the
|
|
96
|
+
* step-up that is not part of it is not shown, so it is REFUSED: the person must never approve something the
|
|
97
|
+
* message does not display.
|
|
98
|
+
*/
|
|
99
|
+
export interface CibaAction {
|
|
100
|
+
verb: string;
|
|
101
|
+
/** Plain non-negative decimal, shown in full. Present together with `currency` and `payee`. */
|
|
102
|
+
amount?: string;
|
|
103
|
+
/** 3-letter currency code, upper-cased; always shown next to the amount. */
|
|
104
|
+
currency?: string;
|
|
105
|
+
/** Who receives the value. Required whenever `amount` is present. */
|
|
106
|
+
payee?: string;
|
|
107
|
+
resource: string;
|
|
108
|
+
}
|
|
109
|
+
/** Plain-ASCII rendering of a payee: itself when ASCII, else the punycode of each word (or \u escapes when IDNA refuses). */
|
|
110
|
+
export declare function asciiForm(payee: string): string;
|
|
111
|
+
/**
|
|
112
|
+
* Build the canonical action from a step-up. Fail loud (R3-05): unknown `params` keys, a nested or malformed amount,
|
|
113
|
+
* a missing currency or payee next to an amount, two different payee fields, and non-identifier verb / resource all throw.
|
|
114
|
+
*/
|
|
115
|
+
export declare function cibaActionFromStepUp(stepUp: StepUpRequest): CibaAction;
|
|
66
116
|
/**
|
|
67
117
|
* Map a PCA {@link StepUpRequest} to a {@link CibaAuthRequest}. Pure: derives a stable `auth_req_id`
|
|
68
118
|
* from the step-up id, renders the `binding_message`, and carries the scope / expiry / poll interval.
|
|
@@ -97,6 +147,19 @@ export interface CibaBrokerOptions {
|
|
|
97
147
|
*/
|
|
98
148
|
onComplete?: (session: CibaSession) => void;
|
|
99
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* What a CIBA token request (CIBA Core 10.1 / 11) gets back from the broker: `ok` exactly once on
|
|
152
|
+
* approval; otherwise the OAuth `error` the token endpoint must return. After `slow_down`, `interval`
|
|
153
|
+
* is the new minimum spacing in seconds (the old one plus 5, CIBA Core 11).
|
|
154
|
+
*/
|
|
155
|
+
export type CibaTokenOutcome = {
|
|
156
|
+
ok: true;
|
|
157
|
+
session: CibaSession;
|
|
158
|
+
} | {
|
|
159
|
+
ok: false;
|
|
160
|
+
error: 'authorization_pending' | 'slow_down' | 'access_denied' | 'expired_token' | 'invalid_grant';
|
|
161
|
+
interval: number;
|
|
162
|
+
};
|
|
100
163
|
/** The in-memory CIBA broker returned by {@link createCibaBroker}. */
|
|
101
164
|
export interface CibaBroker {
|
|
102
165
|
/** Begin a backchannel flow for a step-up; returns the CIBA auth request (status starts `pending`). */
|
|
@@ -105,6 +168,13 @@ export interface CibaBroker {
|
|
|
105
168
|
poll(auth_req_id: string): {
|
|
106
169
|
status: CibaStatus;
|
|
107
170
|
};
|
|
171
|
+
/**
|
|
172
|
+
* Token-endpoint semantics for POLL mode (CIBA Core 11): enforces the poll `interval` (a request that
|
|
173
|
+
* arrives sooner than `interval` seconds after the previous one gets `slow_down` and the interval grows
|
|
174
|
+
* by 5 s), and makes a successful approval single-use (a replayed `auth_req_id` gets `invalid_grant`).
|
|
175
|
+
* Unlike {@link CibaBroker.poll}, which is a side-effect-free status read.
|
|
176
|
+
*/
|
|
177
|
+
token(auth_req_id: string): CibaTokenOutcome;
|
|
108
178
|
/** The human acts out-of-band: approve or deny. Fires `onComplete` (PING/PUSH) if configured. */
|
|
109
179
|
resolve(auth_req_id: string, decision: 'approve' | 'deny', by: string): CibaSession;
|
|
110
180
|
/** Read a full session snapshot (status computed at read time), or `undefined` if unknown. */
|
|
@@ -145,3 +215,4 @@ export interface CibaCosignResult {
|
|
|
145
215
|
export declare function cibaDecisionToCosign(decision: 'approve' | 'deny', budget: TrustBudget, policy: RiskPolicy, now: number, opts?: {
|
|
146
216
|
full?: boolean;
|
|
147
217
|
}): CibaCosignResult;
|
|
218
|
+
export * from './client';
|
package/dist/index.js
CHANGED
|
@@ -26,41 +26,227 @@
|
|
|
26
26
|
* Everything here is pure or in-memory and authorises nothing on its own: the resource server's verifier
|
|
27
27
|
* (`requirePCA` / the adjudicator) and the FROST cosigners remain the run-time authority.
|
|
28
28
|
*/
|
|
29
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
32
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
33
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
34
|
+
}
|
|
35
|
+
Object.defineProperty(o, k2, desc);
|
|
36
|
+
}) : (function(o, m, k, k2) {
|
|
37
|
+
if (k2 === undefined) k2 = k;
|
|
38
|
+
o[k2] = m[k];
|
|
39
|
+
}));
|
|
40
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
41
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
42
|
+
};
|
|
29
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.asciiForm = asciiForm;
|
|
45
|
+
exports.cibaActionFromStepUp = cibaActionFromStepUp;
|
|
30
46
|
exports.toCibaAuthRequest = toCibaAuthRequest;
|
|
31
47
|
exports.createCibaBroker = createCibaBroker;
|
|
32
48
|
exports.requiresCiba = requiresCiba;
|
|
33
49
|
exports.cibaDecisionToCosign = cibaDecisionToCosign;
|
|
50
|
+
const node_crypto_1 = require("node:crypto");
|
|
51
|
+
const node_url_1 = require("node:url");
|
|
34
52
|
const pca_1 = require("@atlasauth/pca");
|
|
35
53
|
const DEFAULT_EXPIRY_SEC = 300;
|
|
36
54
|
const DEFAULT_INTERVAL_SEC = 5;
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
/** CIBA Core 7.3: `auth_req_id` characters are restricted to A-Z a-z 0-9 . - _ . */
|
|
56
|
+
const AUTH_REQ_ID_RE = /^[A-Za-z0-9._-]+$/;
|
|
57
|
+
/** 128 bits of base64url is 22 characters; reject anything shorter (CIBA Core 7.3). */
|
|
58
|
+
const MIN_AUTH_REQ_ID_LEN = 22;
|
|
59
|
+
/** RFC 6749 3.3 `scope-token`: %x21 / %x23-5B / %x5D-7E. */
|
|
60
|
+
const SCOPE_TOKEN_RE = /^[\x21\x23-\x5B\x5D-\x7E]+$/;
|
|
61
|
+
/** The goal text is free-form (agent / user supplied); cap what is shown to a person on a small screen. */
|
|
62
|
+
const MAX_GOAL_CHARS = 100;
|
|
63
|
+
/**
|
|
64
|
+
* Make untrusted text safe for a one-line, plain-text approval prompt (CIBA Core 7.1: `binding_message`
|
|
65
|
+
* SHOULD be short and use a limited set of plain-text characters): control characters, line breaks and
|
|
66
|
+
* bidi / zero-width formatting characters become spaces, runs of whitespace collapse.
|
|
67
|
+
*/
|
|
68
|
+
function plainText(value) {
|
|
69
|
+
return value
|
|
70
|
+
.replace(/[\p{Cc}\p{Cf}\u2028\u2029]/gu, ' ')
|
|
71
|
+
.replace(/\s+/gu, ' ')
|
|
72
|
+
.trim();
|
|
73
|
+
}
|
|
74
|
+
function clip(value, max) {
|
|
75
|
+
const chars = Array.from(value);
|
|
76
|
+
return chars.length <= max ? value : `${chars.slice(0, max - 1).join('')}…`;
|
|
77
|
+
}
|
|
78
|
+
const FORGED_CLAUSE_RE = /because\s+you\s+asked/i;
|
|
79
|
+
/** Keys of `params` the renderer displays. Every other key makes the request unrenderable. */
|
|
80
|
+
const PAYEE_KEYS = ['payee', 'to', 'recipient', 'beneficiary', 'destination'];
|
|
81
|
+
const DISPLAYED_PARAM_KEYS = new Set(['amount', 'currency', ...PAYEE_KEYS]);
|
|
82
|
+
/** verb / resource are identifiers, never free text: this class cannot hold quotes, spaces, bidi or control characters. */
|
|
83
|
+
const IDENT_RE = /^[A-Za-z0-9][A-Za-z0-9._:/#@+-]{0,63}$/;
|
|
84
|
+
const MAX_PAYEE_CHARS = 64;
|
|
85
|
+
/** Control, format (bidi, zero-width, joiners), line/paragraph separators, specials and unpaired surrogates. */
|
|
86
|
+
const UNDISPLAYABLE_RE = /[\p{Cc}\p{Cf}\p{Cs}\p{Co}\p{Cn}\u2028\u2029\uFFF9-\uFFFD]/u;
|
|
87
|
+
function identifier(value, what) {
|
|
88
|
+
if (typeof value !== 'string' || !IDENT_RE.test(value)) {
|
|
89
|
+
throw new RangeError(`ciba: the step-up ${what} must be a plain identifier (letters, digits and . _ : / # @ + -, at most 64 characters); refusing to render free text in the approval message`);
|
|
90
|
+
}
|
|
91
|
+
if (FORGED_CLAUSE_RE.test(value))
|
|
92
|
+
throw new RangeError(`ciba: the step-up ${what} contains an approval-explanation clause`);
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
function payeeText(value) {
|
|
96
|
+
if (typeof value !== 'string')
|
|
97
|
+
throw new RangeError('ciba: the payee must be a string (a nested value cannot be shown to the approver)');
|
|
98
|
+
const t = value.normalize('NFC');
|
|
99
|
+
if (t.length === 0 || t.trim() !== t || /\s{2,}/u.test(t))
|
|
100
|
+
throw new RangeError('ciba: the payee must be non-empty without leading, trailing or repeated whitespace');
|
|
101
|
+
if (UNDISPLAYABLE_RE.test(t) || /[\r\n\t]/.test(t))
|
|
102
|
+
throw new RangeError('ciba: the payee contains control, bidirectional or invisible characters and cannot be displayed');
|
|
103
|
+
if (/["\\]/.test(t))
|
|
104
|
+
throw new RangeError('ciba: the payee must not contain quote or backslash characters');
|
|
105
|
+
if (Array.from(t).length > MAX_PAYEE_CHARS)
|
|
106
|
+
throw new RangeError(`ciba: the payee is longer than ${String(MAX_PAYEE_CHARS)} characters; refusing to truncate what the person approves`);
|
|
107
|
+
if (FORGED_CLAUSE_RE.test(t))
|
|
108
|
+
throw new RangeError('ciba: the payee contains an approval-explanation clause');
|
|
109
|
+
// R4-13 lookalikes. NFC already composed what can be composed, so any combining mark left is a stacked/decorative one;
|
|
110
|
+
// compatibility forms (fullwidth, ligatures, circled letters) differ from their plain look-alike under NFKC; and a payee
|
|
111
|
+
// that mixes scripts ("Pаypal", Cyrillic а) is the classic homograph. All are refused. A payee in ONE non-Latin script is
|
|
112
|
+
// legitimate, so it is allowed but rendered WITH its ASCII form (see `asciiForm`) so a whole-script look-alike
|
|
113
|
+
// ("аррlе" in Cyrillic) is never shown as just the text it imitates.
|
|
114
|
+
if (/\p{M}/u.test(t))
|
|
115
|
+
throw new RangeError('ciba: the payee contains combining marks and cannot be shown unambiguously');
|
|
116
|
+
if (t.normalize('NFKC') !== t)
|
|
117
|
+
throw new RangeError('ciba: the payee contains compatibility/fullwidth characters that imitate plain ones');
|
|
118
|
+
if (scriptsOf(t).size > 1)
|
|
119
|
+
throw new RangeError('ciba: the payee mixes writing systems (a homograph risk); refusing so the person never approves a look-alike');
|
|
120
|
+
return t;
|
|
121
|
+
}
|
|
122
|
+
/** Writing-system groups present in `t` (letters only; digits, punctuation and spaces are script-neutral). */
|
|
123
|
+
const SCRIPT_GROUPS = [
|
|
124
|
+
['latin', /\p{Script=Latin}/u],
|
|
125
|
+
['cyrillic', /\p{Script=Cyrillic}/u],
|
|
126
|
+
['greek', /\p{Script=Greek}/u],
|
|
127
|
+
['armenian', /\p{Script=Armenian}/u],
|
|
128
|
+
['hebrew', /\p{Script=Hebrew}/u],
|
|
129
|
+
['arabic', /\p{Script=Arabic}/u],
|
|
130
|
+
['cjk', /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Bopomofo}]/u],
|
|
131
|
+
['indic-thai', /[\p{Script=Devanagari}\p{Script=Bengali}\p{Script=Tamil}\p{Script=Thai}\p{Script=Georgian}]/u],
|
|
132
|
+
];
|
|
133
|
+
function scriptsOf(t) {
|
|
134
|
+
const found = new Set();
|
|
135
|
+
for (const ch of t) {
|
|
136
|
+
if (!/\p{L}/u.test(ch))
|
|
137
|
+
continue;
|
|
138
|
+
const g = SCRIPT_GROUPS.find(([, re]) => re.test(ch));
|
|
139
|
+
found.add(g ? g[0] : 'other:' + ch);
|
|
140
|
+
}
|
|
141
|
+
return found;
|
|
142
|
+
}
|
|
143
|
+
/** Plain-ASCII rendering of a payee: itself when ASCII, else the punycode of each word (or \u escapes when IDNA refuses). */
|
|
144
|
+
function asciiForm(payee) {
|
|
145
|
+
if (/^[\x20-\x7E]*$/.test(payee))
|
|
146
|
+
return payee;
|
|
147
|
+
return payee
|
|
148
|
+
.split(' ')
|
|
149
|
+
.map((w) => (/^[\x20-\x7E]*$/.test(w) ? w : (0, node_url_1.domainToASCII)(w) || Array.from(w, (c) => (c.codePointAt(0) > 0x7e ? `\\u{${c.codePointAt(0).toString(16)}}` : c)).join('')))
|
|
150
|
+
.join(' ');
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Build the canonical action from a step-up. Fail loud (R3-05): unknown `params` keys, a nested or malformed amount,
|
|
154
|
+
* a missing currency or payee next to an amount, two different payee fields, and non-identifier verb / resource all throw.
|
|
155
|
+
*/
|
|
156
|
+
function cibaActionFromStepUp(stepUp) {
|
|
157
|
+
const params = (stepUp.params ?? {});
|
|
158
|
+
if (params === null || typeof params !== 'object' || Array.isArray(params))
|
|
159
|
+
throw new RangeError('ciba: step-up params must be an object');
|
|
160
|
+
const unknown = Object.keys(params).filter((k) => !DISPLAYED_PARAM_KEYS.has(k) && params[k] !== undefined);
|
|
161
|
+
if (unknown.length > 0) {
|
|
162
|
+
throw new RangeError(`ciba: step-up params field(s) ${unknown.join(', ')} are not displayed in the approval message (displayable: amount, currency, ${PAYEE_KEYS.join('/')}); refusing so the person never approves a hidden field`);
|
|
163
|
+
}
|
|
164
|
+
const present = (v) => v !== undefined && v !== null;
|
|
165
|
+
const action = { verb: identifier(stepUp.verb, 'verb'), resource: identifier(stepUp.resource, 'resource') };
|
|
166
|
+
const payeeKeys = PAYEE_KEYS.filter((k) => present(params[k]));
|
|
167
|
+
if (payeeKeys.length > 1)
|
|
168
|
+
throw new RangeError(`ciba: more than one payee field (${payeeKeys.join(', ')}) in params; the approver would see only one`);
|
|
169
|
+
const hasAmount = present(params['amount']);
|
|
170
|
+
if (hasAmount) {
|
|
171
|
+
const amt = params['amount'];
|
|
172
|
+
const text = typeof amt === 'number' && Number.isFinite(amt) ? String(amt) : typeof amt === 'string' ? amt : '';
|
|
173
|
+
if (!PLAIN_AMOUNT_RE.test(text))
|
|
174
|
+
throw new RangeError('ciba: the binding message needs a plain non-negative decimal amount (no sign or exponent)');
|
|
175
|
+
const cur = params['currency'];
|
|
176
|
+
if (typeof cur !== 'string' || !CURRENCY_RE.test(cur))
|
|
177
|
+
throw new RangeError('ciba: the binding message needs a 3-letter currency code next to the amount');
|
|
178
|
+
if (payeeKeys.length === 0)
|
|
179
|
+
throw new RangeError('ciba: an amount needs a payee (payee / to / recipient / beneficiary / destination) so the approver sees who receives it');
|
|
180
|
+
action.amount = text;
|
|
181
|
+
action.currency = cur.toUpperCase();
|
|
47
182
|
}
|
|
48
|
-
|
|
183
|
+
else if (present(params['currency'])) {
|
|
184
|
+
throw new RangeError('ciba: a currency without an amount cannot be displayed');
|
|
185
|
+
}
|
|
186
|
+
if (payeeKeys.length === 1)
|
|
187
|
+
action.payee = payeeText(params[payeeKeys[0]]);
|
|
188
|
+
return action;
|
|
49
189
|
}
|
|
190
|
+
/** A plain non-negative decimal: no sign, no exponent, no leading junk. */
|
|
191
|
+
const PLAIN_AMOUNT_RE = /^(?:0|[1-9][0-9]*)(?:\.[0-9]+)?$/;
|
|
192
|
+
const CURRENCY_RE = /^[A-Za-z]{3}$/;
|
|
50
193
|
/**
|
|
51
|
-
* Build the CIBA `binding_message`: the one-line human-readable approval context
|
|
52
|
-
* verb
|
|
53
|
-
*
|
|
54
|
-
*
|
|
194
|
+
* Build the CIBA `binding_message`: the one-line human-readable approval context, in the FIXED order
|
|
195
|
+
* `Approve <verb> <amount> <CUR> to "<payee>" on <resource>`. The head is built from the canonical action and is NEVER
|
|
196
|
+
* truncated; only the optional goal-lineage clause ("because you asked <agent> to '<goal>'") may shrink or drop to fit
|
|
197
|
+
* `maxChars`. If the head alone does not fit, throw. Falls back to the salted goal commitment when the plaintext goal
|
|
198
|
+
* isn't carried on the step-up.
|
|
55
199
|
*/
|
|
56
|
-
function bindingMessage(stepUp, actsFor) {
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
?
|
|
200
|
+
function bindingMessage(stepUp, actsFor, maxChars) {
|
|
201
|
+
const a = cibaActionFromStepUp(stepUp);
|
|
202
|
+
const head = `Approve ${a.verb}` +
|
|
203
|
+
(a.amount !== undefined ? ` ${a.amount} ${a.currency}` : '') +
|
|
204
|
+
(a.payee !== undefined ? ` to "${a.payee}"${/^[\x20-\x7E]*$/.test(a.payee) ? '' : ` [non-ASCII name; ASCII form: ${asciiForm(a.payee)}]`}` : '') +
|
|
205
|
+
` on ${a.resource}`;
|
|
206
|
+
const limit = maxChars ?? Infinity;
|
|
207
|
+
if (Array.from(head).length > limit) {
|
|
208
|
+
throw new RangeError(`ciba: the binding message needs ${String(Array.from(head).length)} characters but bindingMessage.maxChars is ${String(maxChars)}; refusing to truncate what the person approves`);
|
|
209
|
+
}
|
|
210
|
+
const plainGoal = stepUp.goal !== undefined ? plainText(stepUp.goal).replace(/['\u2018\u2019]/g, '\u2032') : '';
|
|
211
|
+
const goalText = plainGoal.length > 0
|
|
212
|
+
? clip(plainGoal, MAX_GOAL_CHARS)
|
|
60
213
|
: stepUp.goalCommit.length > 0
|
|
61
214
|
? `goal ${stepUp.goalCommit.slice(0, 10)}…`
|
|
62
215
|
: undefined;
|
|
63
|
-
|
|
216
|
+
if (goalText === undefined)
|
|
217
|
+
return head;
|
|
218
|
+
const prefix = ` — because you asked ${actsFor} to '`;
|
|
219
|
+
const room = limit - Array.from(head + prefix).length - 1;
|
|
220
|
+
if (room >= Array.from(goalText).length)
|
|
221
|
+
return `${head}${prefix}${goalText}'`;
|
|
222
|
+
if (room >= 8)
|
|
223
|
+
return `${head}${prefix}${clip(goalText, room)}'`;
|
|
224
|
+
return head;
|
|
225
|
+
}
|
|
226
|
+
function tokenise(value) {
|
|
227
|
+
return value.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/-{2,}/g, '-').replace(/^[-.]+|[-.]+$/g, '');
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* The compact, provider-safe rendering used by `bindingMessage: { tokenOnly: true }`, same fixed order:
|
|
231
|
+
* `Approve-<verb>-<amount>-<CUR>-to-<payee>-<resource>`. The message is the human's only view of what they approve,
|
|
232
|
+
* so it is all-or-nothing: the same canonical action as the rich form, a payee that is not plain ASCII (tokenising
|
|
233
|
+
* would silently drop characters) or a limit that would cut any field throws instead of sending a different message.
|
|
234
|
+
*/
|
|
235
|
+
function compactBindingMessage(stepUp, maxChars) {
|
|
236
|
+
const a = cibaActionFromStepUp(stepUp);
|
|
237
|
+
if (a.payee !== undefined && !/^[\x20-\x7E]+$/.test(a.payee)) {
|
|
238
|
+
throw new RangeError('ciba: tokenOnly binding message needs an ASCII payee (tokenising would drop characters the person must see)');
|
|
239
|
+
}
|
|
240
|
+
const raw = ['Approve', a.verb, ...(a.amount !== undefined ? [a.amount, a.currency] : []), ...(a.payee !== undefined ? ['to', a.payee] : []), a.resource];
|
|
241
|
+
const parts = raw.map(tokenise);
|
|
242
|
+
if (parts.some((p) => p.length === 0)) {
|
|
243
|
+
throw new RangeError('ciba: tokenOnly binding message cannot represent the verb, payee or resource');
|
|
244
|
+
}
|
|
245
|
+
const out = parts.join('-');
|
|
246
|
+
if (out.length > maxChars) {
|
|
247
|
+
throw new RangeError(`ciba: the binding message needs ${String(out.length)} characters but bindingMessage.maxChars is ${String(maxChars)}; refusing to truncate what the person approves`);
|
|
248
|
+
}
|
|
249
|
+
return out;
|
|
64
250
|
}
|
|
65
251
|
/**
|
|
66
252
|
* Map a PCA {@link StepUpRequest} to a {@link CibaAuthRequest}. Pure: derives a stable `auth_req_id`
|
|
@@ -68,14 +254,39 @@ function bindingMessage(stepUp, actsFor) {
|
|
|
68
254
|
* Does not start a flow or notify anyone — that's the broker.
|
|
69
255
|
*/
|
|
70
256
|
function toCibaAuthRequest(stepUp, opts = {}) {
|
|
71
|
-
const actsFor = opts.actsFor !== undefined && opts.actsFor.length > 0 ? opts.actsFor : 'your agent';
|
|
72
|
-
const
|
|
257
|
+
const actsFor = opts.actsFor !== undefined && plainText(opts.actsFor).length > 0 ? clip(plainText(opts.actsFor), 40) : 'your agent';
|
|
258
|
+
const requestedExpiry = opts.expiresInSec !== undefined ? opts.expiresInSec : DEFAULT_EXPIRY_SEC;
|
|
259
|
+
if (!Number.isSafeInteger(requestedExpiry) || requestedExpiry <= 0) {
|
|
260
|
+
throw new RangeError(`ciba: requested_expiry must be a positive integer number of seconds, got ${String(requestedExpiry)}`);
|
|
261
|
+
}
|
|
262
|
+
// The verb is spliced into ONE scope-token. A space in it would otherwise smuggle in extra scope tokens.
|
|
263
|
+
const stepUpScope = `urn:atlas:pca:stepup:${stepUp.verb}`;
|
|
264
|
+
if (!SCOPE_TOKEN_RE.test(stepUpScope)) {
|
|
265
|
+
throw new RangeError('ciba: the step-up verb cannot be carried as an OAuth scope-token (RFC 6749 3.3)');
|
|
266
|
+
}
|
|
267
|
+
const scope = opts.stepUpScope === false ? 'openid' : `openid ${stepUpScope}`;
|
|
268
|
+
const interval = opts.interval !== undefined ? opts.interval : DEFAULT_INTERVAL_SEC;
|
|
269
|
+
if (!Number.isSafeInteger(interval) || interval <= 0) {
|
|
270
|
+
throw new RangeError(`ciba: interval must be a positive integer number of seconds, got ${String(interval)}`);
|
|
271
|
+
}
|
|
272
|
+
const auth_req_id = opts.authReqId ?? (0, pca_1.hashCanonical)({ d: 'atlas-pca/ciba/auth_req_id/v1', stepUp: stepUp.id });
|
|
273
|
+
if (!AUTH_REQ_ID_RE.test(auth_req_id) || auth_req_id.length < MIN_AUTH_REQ_ID_LEN || auth_req_id.length > 1024) {
|
|
274
|
+
throw new RangeError('ciba: auth_req_id must use only A-Za-z0-9.-_ and be 22..1024 characters (CIBA Core 7.3)');
|
|
275
|
+
}
|
|
276
|
+
const bm = opts.bindingMessage;
|
|
277
|
+
if (bm?.maxChars !== undefined && (!Number.isSafeInteger(bm.maxChars) || bm.maxChars < 1)) {
|
|
278
|
+
throw new RangeError('ciba: bindingMessage.maxChars must be a positive integer');
|
|
279
|
+
}
|
|
280
|
+
const maxChars = bm?.maxChars ?? 50;
|
|
281
|
+
const binding_message = bm?.tokenOnly === true
|
|
282
|
+
? compactBindingMessage(stepUp, maxChars)
|
|
283
|
+
: bindingMessage(stepUp, actsFor, bm?.maxChars);
|
|
73
284
|
return {
|
|
74
285
|
auth_req_id,
|
|
75
|
-
binding_message
|
|
76
|
-
scope
|
|
77
|
-
requested_expiry:
|
|
78
|
-
interval
|
|
286
|
+
binding_message,
|
|
287
|
+
scope,
|
|
288
|
+
requested_expiry: requestedExpiry,
|
|
289
|
+
interval,
|
|
79
290
|
...(opts.loginHint !== undefined ? { login_hint: opts.loginHint } : {}),
|
|
80
291
|
stepUpId: stepUp.id,
|
|
81
292
|
tier: stepUp.tier,
|
|
@@ -112,16 +323,30 @@ function snapshot(s, now) {
|
|
|
112
323
|
function createCibaBroker(opts = {}) {
|
|
113
324
|
const clock = opts.now ?? Date.now;
|
|
114
325
|
const sessions = new Map();
|
|
326
|
+
/** step-up id -> the auth_req_id of its live (pending or approved) flow, so a repeated `start` is idempotent. */
|
|
327
|
+
const liveByStepUp = new Map();
|
|
115
328
|
return {
|
|
116
329
|
start(stepUp, reqOpts) {
|
|
117
|
-
const
|
|
118
|
-
const
|
|
330
|
+
const now = clock();
|
|
331
|
+
const existingId = liveByStepUp.get(stepUp.id);
|
|
332
|
+
const existing = existingId !== undefined ? sessions.get(existingId) : undefined;
|
|
333
|
+
if (existing !== undefined) {
|
|
334
|
+
const st = effectiveStatus(existing, now);
|
|
335
|
+
// Never reset a flow that is still waiting or already approved: that would silently discard a decision.
|
|
336
|
+
if (st === 'pending' || st === 'approved')
|
|
337
|
+
return existing.request;
|
|
338
|
+
}
|
|
339
|
+
// CIBA Core 7.3: an unguessable auth_req_id (160 random bits, base64url) per flow.
|
|
340
|
+
const request = toCibaAuthRequest(stepUp, { ...reqOpts, authReqId: (0, node_crypto_1.randomBytes)(20).toString('base64url') });
|
|
341
|
+
const createdAt = now;
|
|
119
342
|
const stored = {
|
|
120
343
|
request,
|
|
121
344
|
createdAt,
|
|
122
345
|
expiresAt: createdAt + request.requested_expiry * 1000,
|
|
346
|
+
interval: request.interval,
|
|
123
347
|
};
|
|
124
348
|
sessions.set(request.auth_req_id, stored);
|
|
349
|
+
liveByStepUp.set(stepUp.id, request.auth_req_id);
|
|
125
350
|
return request;
|
|
126
351
|
},
|
|
127
352
|
poll(auth_req_id) {
|
|
@@ -130,6 +355,29 @@ function createCibaBroker(opts = {}) {
|
|
|
130
355
|
throw new Error(`ciba: unknown auth_req_id ${auth_req_id}`);
|
|
131
356
|
return { status: effectiveStatus(s, clock()) };
|
|
132
357
|
},
|
|
358
|
+
token(auth_req_id) {
|
|
359
|
+
const s = sessions.get(auth_req_id);
|
|
360
|
+
if (!s)
|
|
361
|
+
return { ok: false, error: 'invalid_grant', interval: DEFAULT_INTERVAL_SEC };
|
|
362
|
+
const now = clock();
|
|
363
|
+
if (s.consumed)
|
|
364
|
+
return { ok: false, error: 'invalid_grant', interval: s.interval };
|
|
365
|
+
const tooSoon = s.lastPollAt !== undefined && now - s.lastPollAt < s.interval * 1000;
|
|
366
|
+
s.lastPollAt = now;
|
|
367
|
+
if (tooSoon) {
|
|
368
|
+
s.interval += 5;
|
|
369
|
+
return { ok: false, error: 'slow_down', interval: s.interval };
|
|
370
|
+
}
|
|
371
|
+
const st = effectiveStatus(s, now);
|
|
372
|
+
if (st === 'pending')
|
|
373
|
+
return { ok: false, error: 'authorization_pending', interval: s.interval };
|
|
374
|
+
if (st === 'denied')
|
|
375
|
+
return { ok: false, error: 'access_denied', interval: s.interval };
|
|
376
|
+
if (st === 'expired')
|
|
377
|
+
return { ok: false, error: 'expired_token', interval: s.interval };
|
|
378
|
+
s.consumed = true;
|
|
379
|
+
return { ok: true, session: snapshot(s, now) };
|
|
380
|
+
},
|
|
133
381
|
resolve(auth_req_id, decision, by) {
|
|
134
382
|
const s = sessions.get(auth_req_id);
|
|
135
383
|
if (!s)
|
|
@@ -178,4 +426,5 @@ function cibaDecisionToCosign(decision, budget, policy, now, opts = {}) {
|
|
|
178
426
|
return { budget: (0, pca_1.applyCosign)(budget, policy, now, opts), cosigned: true };
|
|
179
427
|
return { budget, cosigned: false };
|
|
180
428
|
}
|
|
429
|
+
__exportStar(require("./client"), exports);
|
|
181
430
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/pca-ciba",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "CIBA (Client-Initiated Backchannel Authentication) bridge for PCA FROST step-up: turn a step-up request into a backchannel human-approval flow with risk-adaptive gating.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ciba",
|
|
@@ -32,9 +32,10 @@
|
|
|
32
32
|
"./package.json": "./package.json"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@atlasauth/pca": "0.
|
|
35
|
+
"@atlasauth/pca": "0.4.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
+
"openid-client": "6.8.2",
|
|
38
39
|
"typescript": "^5.6.3",
|
|
39
40
|
"vitest": "^2.1.4"
|
|
40
41
|
},
|