@atlasauth/js 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # @atlasauth/js changelog
2
2
 
3
- ## Unreleased
3
+ ## 0.25.0 — 2026-10-27
4
+
5
+ - `signInWithSrp` and `srpClientStart`: SRP-6a password sign-in (RFC 5054, 3072-bit group, SHA-256), so the password never leaves the browser.
6
+ - `listAuthorizedApps`, `disconnectAuthorizedApp` and `revokeAppGrant`: the apps a user authorized, with the OpenID Grant Management grants each holds.
7
+ - Identity governance for the signed-in user: `listAccessCatalog`, `requestAccess`, `listMyAccess`, `listMyAccessRequests`, `getAccessRequest`, `cancelAccessRequest`, `listPendingApprovals`, `decideAccessRequest`, `listAccessReviews`, `decideAccessReview`, `listAccessDelegations`, `delegateApprovals` and `endDelegation`.
8
+ - Connections: `revokeMyConnection` and `revokeOrganizationConnection` return `provider_revoked` (true, false or `'unsupported'`), `provider_status`, `provider_error` and `local_cleared`; `AppConnection.last_error` carries the provider's code and HTTP status and `refresh_failures`.
9
+ - Connections: `setOrganizationConnectionCredentials` takes every credential field (bearer token, basic username and password, custom header value, HMAC secret, signing key, OAuth 1.0a keys), `expiresAt` and `config`; `AppConnection.kind` lists the new kinds and carries `secret_expires_at`. There is still no call that reads a credential back.
10
+ - Connections: `connectMyConnection`, `connectOrganizationConnection`, `revokeOrganizationConnection`, `listOrganizationOAuthClients`, `setOrganizationOAuthClient`, `deleteOrganizationOAuthClient`; `AppConnection` carries `environment`, `external_id`, `host_params`, `scopes`, `metadata` and `last_error`, and its status adds `revoked` and `error`.
11
+ - User-managed access for resource owners: `listUmaResources`, `shareUmaResource`, `unshareUmaResource`, `listUmaAccessRequests` and `decideUmaAccessRequest`, with a typed `UmaError`, plus `umaClaimsUrl` and `parseUmaClaimsRedirect` for the claims-gathering redirect.
4
12
 
5
13
  ## 0.24.0 — 2026-10-26
6
14
 
@@ -0,0 +1,42 @@
1
+ import type { FapiClient } from './fapi';
2
+ /**
3
+ * The signed-in user's authorized apps: the third-party OAuth clients they signed
4
+ * in to with this application, and the grants (OpenID Grant Management `grant_id`s)
5
+ * each holds. Cookie-authenticated through the {@link FapiClient}
6
+ * (`/v1/client/me/oauth_grants`, `/v1/client/me/managed_grants`).
7
+ */
8
+ /** One grant an app holds for the user; withdrawing it ends every token issued under it. */
9
+ export interface AppGrant {
10
+ id: string;
11
+ scopes: string[];
12
+ /** The API the grant covers, when it is for one. */
13
+ resource: string | null;
14
+ created_at: number;
15
+ updated_at: number;
16
+ }
17
+ export interface AuthorizedApp {
18
+ object: 'oauth_grant';
19
+ /** The remembered consent's id; pass it to {@link disconnectAuthorizedApp}. */
20
+ id: string;
21
+ client_id: string | null;
22
+ name: string;
23
+ logo_url: string | null;
24
+ first_party: boolean;
25
+ scopes: string[];
26
+ grants: AppGrant[];
27
+ created_at: number;
28
+ }
29
+ /** A refused request; `code` is the server's stable error code. */
30
+ export declare class AuthorizedAppsError extends Error {
31
+ readonly status: number;
32
+ readonly code: string;
33
+ constructor(status: number, code: string, message: string);
34
+ }
35
+ /** The apps this user authorized, each with the grants it holds. */
36
+ export declare function listAuthorizedApps(client: FapiClient): Promise<AuthorizedApp[]>;
37
+ /** Forget an app entirely: its consent, every grant and every live token. */
38
+ export declare function disconnectAuthorizedApp(client: FapiClient, consentId: string): Promise<void>;
39
+ /** Withdraw one grant of an app, leaving its other grants alone. Every token issued under it ends at once. */
40
+ export declare function revokeAppGrant(client: FapiClient, grantId: string): Promise<{
41
+ tokensEnded: number;
42
+ }>;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthorizedAppsError = void 0;
4
+ exports.listAuthorizedApps = listAuthorizedApps;
5
+ exports.disconnectAuthorizedApp = disconnectAuthorizedApp;
6
+ exports.revokeAppGrant = revokeAppGrant;
7
+ /** A refused request; `code` is the server's stable error code. */
8
+ class AuthorizedAppsError extends Error {
9
+ status;
10
+ code;
11
+ constructor(status, code, message) {
12
+ super(message);
13
+ this.name = 'AuthorizedAppsError';
14
+ this.status = status;
15
+ this.code = code;
16
+ }
17
+ }
18
+ exports.AuthorizedAppsError = AuthorizedAppsError;
19
+ async function call(client, path, init) {
20
+ const res = await client.request(path, init);
21
+ if (!res.ok || !res.data) {
22
+ const first = res.errors[0];
23
+ throw new AuthorizedAppsError(res.status, first?.code ?? 'UNKNOWN', first?.message ?? 'The request failed.');
24
+ }
25
+ return res.data;
26
+ }
27
+ /** The apps this user authorized, each with the grants it holds. */
28
+ async function listAuthorizedApps(client) {
29
+ const body = await call(client, '/v1/client/me/oauth_grants', { method: 'GET' });
30
+ return (body.data ?? []).map((app) => ({ ...app, grants: app.grants ?? [] }));
31
+ }
32
+ /** Forget an app entirely: its consent, every grant and every live token. */
33
+ async function disconnectAuthorizedApp(client, consentId) {
34
+ await call(client, `/v1/client/me/oauth_grants/${encodeURIComponent(consentId)}`, { method: 'DELETE' });
35
+ }
36
+ /** Withdraw one grant of an app, leaving its other grants alone. Every token issued under it ends at once. */
37
+ async function revokeAppGrant(client, grantId) {
38
+ const body = await call(client, `/v1/client/me/managed_grants/${encodeURIComponent(grantId)}`, { method: 'DELETE' });
39
+ return { tokensEnded: body.tokens_ended ?? 0 };
40
+ }
41
+ //# sourceMappingURL=authorized-apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorized-apps.js","sourceRoot":"","sources":["../src/authorized-apps.ts"],"names":[],"mappings":";;;AAsDA,gDAGC;AAGD,0DAEC;AAGD,wCAGC;AApCD,mEAAmE;AACnE,MAAa,mBAAoB,SAAQ,KAAK;IACnC,MAAM,CAAS;IACf,IAAI,CAAS;IACtB,YAAY,MAAc,EAAE,IAAY,EAAE,OAAe;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AATD,kDASC;AAED,KAAK,UAAU,IAAI,CAAI,MAAkB,EAAE,IAAY,EAAE,IAAiB;IACxE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAAI,IAAI,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,IAAI,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,SAAS,EAAE,KAAK,EAAE,OAAO,IAAI,qBAAqB,CAAC,CAAC;IAC/G,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,oEAAoE;AAC7D,KAAK,UAAU,kBAAkB,CAAC,MAAkB;IACzD,MAAM,IAAI,GAAG,MAAM,IAAI,CAA6B,MAAM,EAAE,4BAA4B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7G,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,6EAA6E;AACtE,KAAK,UAAU,uBAAuB,CAAC,MAAkB,EAAE,SAAiB;IACjF,MAAM,IAAI,CAAC,MAAM,EAAE,8BAA8B,kBAAkB,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC1G,CAAC;AAED,8GAA8G;AACvG,KAAK,UAAU,cAAc,CAAC,MAAkB,EAAE,OAAe;IACtE,MAAM,IAAI,GAAG,MAAM,IAAI,CAA4B,MAAM,EAAE,gCAAgC,kBAAkB,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChJ,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,CAAC,EAAE,CAAC;AACjD,CAAC"}
@@ -5,7 +5,7 @@ import type { FapiClient } from './fapi';
5
5
  * an OAuth account a member shared), with live status. Authorizing an OAuth
6
6
  * connection uses `connectExternalAccount` / `reauthorizeExternalAccount`.
7
7
  */
8
- export type ConnectionStatus = 'connected' | 'not_connected' | 'needs_reauth';
8
+ export type ConnectionStatus = 'connected' | 'not_connected' | 'needs_reauth' | 'revoked' | 'error';
9
9
  export interface AppConnection {
10
10
  object: 'connection';
11
11
  id: string;
@@ -13,20 +13,121 @@ export interface AppConnection {
13
13
  type: 'organization' | 'user';
14
14
  id: string;
15
15
  };
16
- kind: 'oauth' | 'api_key' | 'client_credentials';
16
+ kind: 'oauth' | 'api_key' | 'client_credentials' | 'bearer' | 'basic' | 'custom_header' | 'hmac_secret' | 'jwt_bearer' | 'oauth1' | 'github_app_installation' | 'admin_consent';
17
17
  provider: string;
18
18
  name: string;
19
19
  allowed_hosts: string[];
20
20
  status: ConnectionStatus;
21
+ /** Always `data`: a connection is never a sign-in method. */
22
+ purpose?: 'data';
23
+ environment?: 'production' | 'sandbox';
24
+ sandbox?: boolean;
25
+ /** The provider-side account the connection covers (a company, a workspace, a user id). */
26
+ external_id?: string | null;
27
+ host_params?: Record<string, string>;
28
+ scopes?: string[];
29
+ expires_at?: number | null;
30
+ /** Non-secret provider handles captured with the token (realmId, instance_url, team_id...). */
31
+ metadata?: Record<string, string>;
32
+ /** The provider's own error behind the status (`invalid_grant`, ...), with the HTTP status it answered. */
33
+ last_error?: {
34
+ code: string;
35
+ message: string;
36
+ httpStatus?: number | null;
37
+ at: number;
38
+ } | null;
39
+ /** Consecutive failed refreshes; 0 when healthy. */
40
+ refresh_failures?: number;
41
+ /** @deprecated Always null: a connection owns its tokens. */
21
42
  external_account_id: string | null;
22
43
  has_secret: boolean;
44
+ /** When the entered credential expires (epoch ms). The credential itself is never readable from the browser. */
45
+ secret_expires_at?: number | null;
23
46
  }
24
- /** Credential to enter for an api_key or client_credentials connection. Write-only. */
47
+ /** What the provider said when a connection was disconnected. The stored token is cleared in every case. */
48
+ export interface ConnectionRevokeResult {
49
+ /** `true` the provider confirmed; `'unsupported'` it has no revoke endpoint; `false` it refused or was unreachable (see `provider_error`). */
50
+ provider_revoked: boolean | 'unsupported' | 'not_connected';
51
+ provider_status: number | null;
52
+ provider_error: {
53
+ code: string;
54
+ description: string | null;
55
+ } | null;
56
+ local_cleared: true;
57
+ }
58
+ /** What to send when starting the provider authorization of a connection. */
59
+ export interface ConnectConnectionInput {
60
+ /** Where the owner lands afterwards; the URL carries `__atlas_status=connected` and `__atlas_connection=<id>`. */
61
+ redirectUrl: string;
62
+ /** Values for the provider's host templates, e.g. `{ subdomain: 'acme' }` or `{ tenant: 'contoso.onmicrosoft.com' }`. */
63
+ hostParams?: Record<string, string>;
64
+ environment?: 'production' | 'sandbox';
65
+ additionalScopes?: string[];
66
+ loginHint?: string;
67
+ display?: 'redirect' | 'popup';
68
+ /** A different provider account than the connection holds creates a sibling instead of failing with 409. */
69
+ createIfNew?: boolean;
70
+ }
71
+ export interface ConnectionAuthorization {
72
+ object: 'connection_authorization';
73
+ connection_id: string;
74
+ authorization_url: string;
75
+ attempt_id: string;
76
+ }
77
+ /** An organization's own OAuth client for a provider (the secret is write-only). */
78
+ export interface ConnectionOAuthClient {
79
+ object: 'connection_oauth_client';
80
+ id: string;
81
+ provider: string;
82
+ environment: 'production' | 'sandbox';
83
+ client_id: string;
84
+ has_secret: true;
85
+ scopes: string[];
86
+ host_params: Record<string, string>;
87
+ enabled: boolean;
88
+ callback_url: string;
89
+ }
90
+ export interface SetConnectionOAuthClientInput {
91
+ provider: string;
92
+ environment?: 'production' | 'sandbox';
93
+ clientId: string;
94
+ /** Required the first time; omit to keep the stored secret. */
95
+ clientSecret?: string;
96
+ scopes?: string[];
97
+ hostParams?: Record<string, string>;
98
+ enabled?: boolean;
99
+ }
100
+ /**
101
+ * Credential to enter for a non-OAuth connection. Write-only: it is sealed server-side and no browser call can read it
102
+ * back. Which fields apply depends on the connection's kind.
103
+ */
25
104
  export interface ConnectionCredentialsInput {
105
+ /** api_key */
26
106
  apiKey?: string;
107
+ /** bearer */
108
+ token?: string;
109
+ /** basic */
110
+ username?: string;
111
+ password?: string;
112
+ /** custom_header */
113
+ value?: string;
114
+ /** hmac_secret */
115
+ secret?: string;
116
+ /** client_credentials */
27
117
  clientId?: string;
28
118
  clientSecret?: string;
29
119
  tokenUrl?: string;
120
+ /** jwt_bearer / github_app_installation: a PEM private key, or (jwt_bearer) a Google service-account JSON key. */
121
+ privateKey?: string;
122
+ serviceAccountJson?: string;
123
+ /** oauth1 */
124
+ consumerKey?: string;
125
+ consumerSecret?: string;
126
+ tokenSecret?: string;
127
+ /** Epoch milliseconds or an ISO date; reminders go out 30, 7 and 1 days before. */
128
+ expiresAt?: number | string;
129
+ /** Non-secret settings of the kind (placement, header name, algorithm...). */
130
+ config?: Record<string, unknown>;
30
131
  }
31
132
  export declare class ConnectionRequestError extends Error {
32
133
  readonly status: number;
@@ -41,3 +142,20 @@ export declare function listOrganizationConnections(client: FapiClient, organiza
41
142
  export declare function setOrganizationConnectionCredentials(client: FapiClient, organizationId: string, connectionId: string, input: ConnectionCredentialsInput): Promise<AppConnection>;
42
143
  /** Share the signed-in admin's own linked provider account with the organization. */
43
144
  export declare function shareOrganizationConnection(client: FapiClient, organizationId: string, connectionId: string): Promise<AppConnection>;
145
+ /**
146
+ * Connect (or reconnect) one of the signed-in user's own connections. Navigate to `authorization_url`. This stores the
147
+ * tokens on the connection: it adds no sign-in method and needs no step-up.
148
+ */
149
+ export declare function connectMyConnection(client: FapiClient, connectionId: string, input: ConnectConnectionInput): Promise<ConnectionAuthorization>;
150
+ /** Disconnect one of the signed-in user's own connections. The answer says whether the provider confirmed the revoke. */
151
+ export declare function revokeMyConnection(client: FapiClient, connectionId: string): Promise<AppConnection & ConnectionRevokeResult>;
152
+ /** Connect (or reconnect) an organization's connection (needs the org profile-manage permission, not a step-up). */
153
+ export declare function connectOrganizationConnection(client: FapiClient, organizationId: string, connectionId: string, input: ConnectConnectionInput): Promise<ConnectionAuthorization>;
154
+ /** Disconnect an organization's connection. */
155
+ export declare function revokeOrganizationConnection(client: FapiClient, organizationId: string, connectionId: string): Promise<AppConnection & ConnectionRevokeResult>;
156
+ /** The organization's own OAuth clients. */
157
+ export declare function listOrganizationOAuthClients(client: FapiClient, organizationId: string): Promise<ConnectionOAuthClient[]>;
158
+ /** Set the organization's own OAuth client for a provider; it overrides the instance client for its connections. */
159
+ export declare function setOrganizationOAuthClient(client: FapiClient, organizationId: string, input: SetConnectionOAuthClientInput): Promise<ConnectionOAuthClient>;
160
+ /** Delete the organization's OAuth client (refused while its connections hold tokens it issued). */
161
+ export declare function deleteOrganizationOAuthClient(client: FapiClient, organizationId: string, clientId: string): Promise<void>;
@@ -5,6 +5,13 @@ exports.listMyConnections = listMyConnections;
5
5
  exports.listOrganizationConnections = listOrganizationConnections;
6
6
  exports.setOrganizationConnectionCredentials = setOrganizationConnectionCredentials;
7
7
  exports.shareOrganizationConnection = shareOrganizationConnection;
8
+ exports.connectMyConnection = connectMyConnection;
9
+ exports.revokeMyConnection = revokeMyConnection;
10
+ exports.connectOrganizationConnection = connectOrganizationConnection;
11
+ exports.revokeOrganizationConnection = revokeOrganizationConnection;
12
+ exports.listOrganizationOAuthClients = listOrganizationOAuthClients;
13
+ exports.setOrganizationOAuthClient = setOrganizationOAuthClient;
14
+ exports.deleteOrganizationOAuthClient = deleteOrganizationOAuthClient;
8
15
  class ConnectionRequestError extends Error {
9
16
  status;
10
17
  code;
@@ -35,19 +42,76 @@ async function listOrganizationConnections(client, organizationId) {
35
42
  }
36
43
  /** Enter the organization's credential for a connection (needs the org profile-manage permission). */
37
44
  function setOrganizationConnectionCredentials(client, organizationId, connectionId, input) {
45
+ const map = [
46
+ ['apiKey', 'api_key'], ['token', 'token'], ['username', 'username'], ['password', 'password'], ['value', 'value'], ['secret', 'secret'],
47
+ ['clientId', 'client_id'], ['clientSecret', 'client_secret'], ['tokenUrl', 'token_url'], ['privateKey', 'private_key'],
48
+ ['serviceAccountJson', 'service_account_json'], ['consumerKey', 'consumer_key'], ['consumerSecret', 'consumer_secret'],
49
+ ['tokenSecret', 'token_secret'], ['expiresAt', 'expires_at'], ['config', 'config'],
50
+ ];
38
51
  const body = {};
39
- if (input.apiKey !== undefined)
40
- body.api_key = input.apiKey;
41
- if (input.clientId !== undefined)
42
- body.client_id = input.clientId;
43
- if (input.clientSecret !== undefined)
44
- body.client_secret = input.clientSecret;
45
- if (input.tokenUrl !== undefined)
46
- body.token_url = input.tokenUrl;
52
+ for (const [from, to] of map)
53
+ if (input[from] !== undefined)
54
+ body[to] = input[from];
47
55
  return call(client, `${orgBase(organizationId)}/${encodeURIComponent(connectionId)}/credentials`, { method: 'PUT', body: JSON.stringify(body) });
48
56
  }
49
57
  /** Share the signed-in admin's own linked provider account with the organization. */
50
58
  function shareOrganizationConnection(client, organizationId, connectionId) {
51
59
  return call(client, `${orgBase(organizationId)}/${encodeURIComponent(connectionId)}/share`, { method: 'POST', body: '{}' });
52
60
  }
61
+ const connectBody = (i) => ({
62
+ redirect_url: i.redirectUrl,
63
+ ...(i.hostParams ? { host_params: i.hostParams } : {}),
64
+ ...(i.environment ? { environment: i.environment } : {}),
65
+ ...(i.additionalScopes ? { additional_scopes: i.additionalScopes } : {}),
66
+ ...(i.loginHint ? { login_hint: i.loginHint } : {}),
67
+ ...(i.display ? { display: i.display } : {}),
68
+ ...(i.createIfNew ? { create_if_new: true } : {}),
69
+ });
70
+ /**
71
+ * Connect (or reconnect) one of the signed-in user's own connections. Navigate to `authorization_url`. This stores the
72
+ * tokens on the connection: it adds no sign-in method and needs no step-up.
73
+ */
74
+ function connectMyConnection(client, connectionId, input) {
75
+ return call(client, `/v1/client/me/connections/${encodeURIComponent(connectionId)}/connect`, { method: 'POST', body: JSON.stringify(connectBody(input)) });
76
+ }
77
+ /** Disconnect one of the signed-in user's own connections. The answer says whether the provider confirmed the revoke. */
78
+ function revokeMyConnection(client, connectionId) {
79
+ return call(client, `/v1/client/me/connections/${encodeURIComponent(connectionId)}/revoke`, { method: 'POST', body: '{}' });
80
+ }
81
+ /** Connect (or reconnect) an organization's connection (needs the org profile-manage permission, not a step-up). */
82
+ function connectOrganizationConnection(client, organizationId, connectionId, input) {
83
+ return call(client, `${orgBase(organizationId)}/${encodeURIComponent(connectionId)}/connect`, { method: 'POST', body: JSON.stringify(connectBody(input)) });
84
+ }
85
+ /** Disconnect an organization's connection. */
86
+ function revokeOrganizationConnection(client, organizationId, connectionId) {
87
+ return call(client, `${orgBase(organizationId)}/${encodeURIComponent(connectionId)}/revoke`, { method: 'POST', body: '{}' });
88
+ }
89
+ const clientsBase = (organizationId) => `/v1/client/organizations/${encodeURIComponent(organizationId)}/connection_oauth_clients`;
90
+ /** The organization's own OAuth clients. */
91
+ async function listOrganizationOAuthClients(client, organizationId) {
92
+ return (await call(client, clientsBase(organizationId), { method: 'GET' })).data ?? [];
93
+ }
94
+ /** Set the organization's own OAuth client for a provider; it overrides the instance client for its connections. */
95
+ function setOrganizationOAuthClient(client, organizationId, input) {
96
+ return call(client, clientsBase(organizationId), {
97
+ method: 'PUT',
98
+ body: JSON.stringify({
99
+ provider: input.provider,
100
+ ...(input.environment ? { environment: input.environment } : {}),
101
+ client_id: input.clientId,
102
+ ...(input.clientSecret ? { client_secret: input.clientSecret } : {}),
103
+ ...(input.scopes ? { scopes: input.scopes } : {}),
104
+ ...(input.hostParams ? { host_params: input.hostParams } : {}),
105
+ ...(input.enabled !== undefined ? { enabled: input.enabled } : {}),
106
+ }),
107
+ });
108
+ }
109
+ /** Delete the organization's OAuth client (refused while its connections hold tokens it issued). */
110
+ async function deleteOrganizationOAuthClient(client, organizationId, clientId) {
111
+ const res = await client.request(`${clientsBase(organizationId)}/${encodeURIComponent(clientId)}`, { method: 'DELETE' });
112
+ if (!res.ok) {
113
+ const first = res.errors[0];
114
+ throw new ConnectionRequestError(res.status, first?.code ?? 'UNKNOWN', first?.message ?? 'The request failed.');
115
+ }
116
+ }
53
117
  //# sourceMappingURL=connections.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"connections.js","sourceRoot":"","sources":["../src/connections.ts"],"names":[],"mappings":";;;AAsDA,8CAEC;AAGD,kEAEC;AAGD,oFAYC;AAGD,kEAEC;AAlDD,MAAa,sBAAuB,SAAQ,KAAK;IAEpC;IACA;IAFX,YACW,MAAc,EACd,IAAY,EACrB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,WAAM,GAAN,MAAM,CAAQ;QACd,SAAI,GAAJ,IAAI,CAAQ;QAIrB,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AATD,wDASC;AAED,KAAK,UAAU,IAAI,CAAI,MAAkB,EAAE,IAAY,EAAE,IAAiB;IACxE,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAAI,IAAI,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,IAAI,sBAAsB,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,SAAS,EAAE,KAAK,EAAE,OAAO,IAAI,qBAAqB,CAAC,CAAC;IAClH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,cAAsB,EAAE,EAAE,CAAC,4BAA4B,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC;AAEzH,4CAA4C;AACrC,KAAK,UAAU,iBAAiB,CAAC,MAAkB;IACxD,OAAO,CAAC,MAAM,IAAI,CAA4B,MAAM,EAAE,2BAA2B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;AACpH,CAAC;AAED,6CAA6C;AACtC,KAAK,UAAU,2BAA2B,CAAC,MAAkB,EAAE,cAAsB;IAC1F,OAAO,CAAC,MAAM,IAAI,CAA4B,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;AAChH,CAAC;AAED,sGAAsG;AACtG,SAAgB,oCAAoC,CAClD,MAAkB,EAClB,cAAsB,EACtB,YAAoB,EACpB,KAAiC;IAEjC,MAAM,IAAI,GAA2B,EAAE,CAAC;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5D,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC;IAClE,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;QAAE,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,YAAY,CAAC;IAC9E,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC;IAClE,OAAO,IAAI,CAAgB,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,kBAAkB,CAAC,YAAY,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAClK,CAAC;AAED,qFAAqF;AACrF,SAAgB,2BAA2B,CAAC,MAAkB,EAAE,cAAsB,EAAE,YAAoB;IAC1G,OAAO,IAAI,CAAgB,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,kBAAkB,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7I,CAAC"}
1
+ {"version":3,"file":"connections.js","sourceRoot":"","sources":["../src/connections.ts"],"names":[],"mappings":"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"}
package/dist/iga.d.ts ADDED
@@ -0,0 +1,118 @@
1
+ import type { FapiClient } from './fapi';
2
+ import type { FieldError } from './attempt';
3
+ /**
4
+ * Identity governance for the signed-in user: browse what can be requested,
5
+ * request it, follow requests, decide approvals waiting on you, certify access
6
+ * you were asked to review, and hand your approvals to a stand-in.
7
+ */
8
+ export type AccessRisk = 'low' | 'medium' | 'high' | 'critical';
9
+ export type AccessRequestStatus = 'pending' | 'approved' | 'denied' | 'cancelled' | 'fulfilled' | 'failed';
10
+ export interface AccessCatalogItem {
11
+ object: 'iga_catalog_item';
12
+ id: string;
13
+ key: string;
14
+ name: string;
15
+ description: string | null;
16
+ kind: 'role' | 'org_membership' | 'group' | 'resource_role' | 'app_assignment' | 'custom';
17
+ risk_level: AccessRisk;
18
+ /** How many approval steps a request goes through (0 = granted immediately). */
19
+ approval_steps: number;
20
+ max_duration_seconds: number | null;
21
+ require_justification: boolean;
22
+ }
23
+ export interface AccessGrant {
24
+ object: 'iga_grant';
25
+ id: string;
26
+ user_id: string;
27
+ entitlement_id: string;
28
+ source: 'request' | 'admin' | 'birthright' | 'existing';
29
+ status: 'active' | 'revoked' | 'expired';
30
+ granted_at: number;
31
+ /** When a time-bound grant ends; null = until revoked. */
32
+ expires_at: number | null;
33
+ }
34
+ export interface AccessRequest {
35
+ object: 'iga_request';
36
+ id: string;
37
+ entitlement_id: string;
38
+ beneficiary_user_id: string;
39
+ justification: string | null;
40
+ duration_seconds: number | null;
41
+ status: AccessRequestStatus;
42
+ /** The step waiting on a decision (null once the request is final). */
43
+ current_step: number | null;
44
+ steps: Array<{
45
+ index: number;
46
+ type: string;
47
+ mode: 'any' | 'all';
48
+ approvers: string[];
49
+ status: 'pending' | 'approved' | 'denied';
50
+ escalated: boolean;
51
+ }>;
52
+ approvals: Array<{
53
+ step: number;
54
+ approver_user_id: string;
55
+ acting_for_user_id: string | null;
56
+ decision: 'approve' | 'deny';
57
+ comment: string | null;
58
+ decided_at: number;
59
+ }>;
60
+ created_at: number;
61
+ }
62
+ export interface AccessReviewItem {
63
+ object: 'iga_campaign_item';
64
+ id: string;
65
+ campaign_id: string;
66
+ user_id: string;
67
+ entitlement_id: string;
68
+ decision: 'pending' | 'certified' | 'revoked';
69
+ }
70
+ export interface AccessDelegation {
71
+ object: 'iga_delegation';
72
+ id: string;
73
+ delegator_user_id: string;
74
+ delegate_user_id: string;
75
+ starts_at: number;
76
+ ends_at: number;
77
+ }
78
+ export type AccessResult<T> = {
79
+ ok: true;
80
+ data: T;
81
+ } | {
82
+ ok: false;
83
+ errors: FieldError[];
84
+ };
85
+ /** What the signed-in user may request. */
86
+ export declare const listAccessCatalog: (client: FapiClient) => Promise<AccessResult<AccessCatalogItem[]>>;
87
+ /** Access the user holds through governance, with expiry dates. */
88
+ export declare const listMyAccess: (client: FapiClient) => Promise<AccessResult<AccessGrant[]>>;
89
+ export declare const listMyAccessRequests: (client: FapiClient) => Promise<AccessResult<AccessRequest[]>>;
90
+ /**
91
+ * Ask for access. A refusal carries the reason: a missing justification (400), access
92
+ * already held or already requested (409), or a separation-of-duties conflict (409, with
93
+ * `meta.sod`).
94
+ */
95
+ export declare function requestAccess(client: FapiClient, input: {
96
+ entitlement: string;
97
+ justification?: string;
98
+ durationSeconds?: number;
99
+ }): Promise<AccessResult<AccessRequest>>;
100
+ export declare function getAccessRequest(client: FapiClient, id: string): Promise<AccessResult<AccessRequest>>;
101
+ export declare function cancelAccessRequest(client: FapiClient, id: string): Promise<AccessResult<AccessRequest>>;
102
+ /** Requests waiting on this user's decision (their own steps and those delegated to them). */
103
+ export declare const listPendingApprovals: (client: FapiClient) => Promise<AccessResult<AccessRequest[]>>;
104
+ export declare function decideAccessRequest(client: FapiClient, id: string, decision: 'approve' | 'deny', comment?: string): Promise<AccessResult<AccessRequest>>;
105
+ /** Access review items waiting on this user. */
106
+ export declare const listAccessReviews: (client: FapiClient) => Promise<AccessResult<AccessReviewItem[]>>;
107
+ export declare function decideAccessReview(client: FapiClient, id: string, decision: 'certify' | 'revoke', comment?: string): Promise<AccessResult<AccessReviewItem>>;
108
+ export declare const listAccessDelegations: (client: FapiClient) => Promise<AccessResult<AccessDelegation[]>>;
109
+ /** Let another user decide your approvals and reviews until `endsAt` (epoch ms, at most a year out). */
110
+ export declare function delegateApprovals(client: FapiClient, input: {
111
+ delegateUserId: string;
112
+ endsAt: number;
113
+ startsAt?: number;
114
+ }): Promise<AccessResult<AccessDelegation>>;
115
+ export declare function endDelegation(client: FapiClient, id: string): Promise<AccessResult<{
116
+ id: string;
117
+ deleted: true;
118
+ }>>;
package/dist/iga.js ADDED
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listAccessDelegations = exports.listAccessReviews = exports.listPendingApprovals = exports.listMyAccessRequests = exports.listMyAccess = exports.listAccessCatalog = void 0;
4
+ exports.requestAccess = requestAccess;
5
+ exports.getAccessRequest = getAccessRequest;
6
+ exports.cancelAccessRequest = cancelAccessRequest;
7
+ exports.decideAccessRequest = decideAccessRequest;
8
+ exports.decideAccessReview = decideAccessReview;
9
+ exports.delegateApprovals = delegateApprovals;
10
+ exports.endDelegation = endDelegation;
11
+ const P = '/v1/client/me/iga';
12
+ const wrap = (res) => (res.ok && res.data !== null ? { ok: true, data: res.data } : { ok: false, errors: res.errors });
13
+ const list = async (client, path) => {
14
+ const r = wrap(await client.get(path));
15
+ return r.ok ? { ok: true, data: r.data.data } : r;
16
+ };
17
+ /** What the signed-in user may request. */
18
+ const listAccessCatalog = (client) => list(client, `${P}/catalog`);
19
+ exports.listAccessCatalog = listAccessCatalog;
20
+ /** Access the user holds through governance, with expiry dates. */
21
+ const listMyAccess = (client) => list(client, `${P}/grants`);
22
+ exports.listMyAccess = listMyAccess;
23
+ const listMyAccessRequests = (client) => list(client, `${P}/requests`);
24
+ exports.listMyAccessRequests = listMyAccessRequests;
25
+ /**
26
+ * Ask for access. A refusal carries the reason: a missing justification (400), access
27
+ * already held or already requested (409), or a separation-of-duties conflict (409, with
28
+ * `meta.sod`).
29
+ */
30
+ async function requestAccess(client, input) {
31
+ return wrap(await client.post(`${P}/requests`, { entitlement: input.entitlement, justification: input.justification, duration_seconds: input.durationSeconds }));
32
+ }
33
+ async function getAccessRequest(client, id) {
34
+ return wrap(await client.get(`${P}/requests/${encodeURIComponent(id)}`));
35
+ }
36
+ async function cancelAccessRequest(client, id) {
37
+ return wrap(await client.post(`${P}/requests/${encodeURIComponent(id)}/cancel`, {}));
38
+ }
39
+ /** Requests waiting on this user's decision (their own steps and those delegated to them). */
40
+ const listPendingApprovals = (client) => list(client, `${P}/approvals`);
41
+ exports.listPendingApprovals = listPendingApprovals;
42
+ async function decideAccessRequest(client, id, decision, comment) {
43
+ return wrap(await client.post(`${P}/requests/${encodeURIComponent(id)}/decide`, { decision, comment }));
44
+ }
45
+ /** Access review items waiting on this user. */
46
+ const listAccessReviews = (client) => list(client, `${P}/reviews`);
47
+ exports.listAccessReviews = listAccessReviews;
48
+ async function decideAccessReview(client, id, decision, comment) {
49
+ return wrap(await client.post(`${P}/reviews/${encodeURIComponent(id)}/decide`, { decision, comment }));
50
+ }
51
+ const listAccessDelegations = (client) => list(client, `${P}/delegations`);
52
+ exports.listAccessDelegations = listAccessDelegations;
53
+ /** Let another user decide your approvals and reviews until `endsAt` (epoch ms, at most a year out). */
54
+ async function delegateApprovals(client, input) {
55
+ return wrap(await client.post(`${P}/delegations`, { delegate_user_id: input.delegateUserId, ends_at: input.endsAt, starts_at: input.startsAt }));
56
+ }
57
+ async function endDelegation(client, id) {
58
+ return wrap(await client.request(`${P}/delegations/${encodeURIComponent(id)}`, { method: 'DELETE' }));
59
+ }
60
+ //# sourceMappingURL=iga.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iga.js","sourceRoot":"","sources":["../src/iga.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -32,12 +32,14 @@ export * from './mfa-factors';
32
32
  export * from './passkey-sign-in';
33
33
  export * from './passkey-sign-up';
34
34
  export * from './email-code-check';
35
+ export * from './srp';
35
36
  export * from './step-up';
36
37
  export * from './telegram';
37
38
  export * from './siwe';
38
39
  export * from './telemetry';
39
40
  export * from './reauth';
40
41
  export * from './api-keys';
42
+ export * from './authorized-apps';
41
43
  export * from './device-authorization';
42
44
  export * from './app-launcher';
43
45
  export * from './organizations';
@@ -49,6 +51,7 @@ export * from './email-addresses';
49
51
  export * from './account-hints';
50
52
  export * from './custom-challenge';
51
53
  export * from './identity-verification';
54
+ export * from './iga';
52
55
  export * from './profile';
53
56
  export * from './connect';
54
57
  export * from './connections';
@@ -69,3 +72,4 @@ export * from './journey-redirect';
69
72
  export * from './delegated-ui';
70
73
  export * from './external-passkeys';
71
74
  export * from './credentials';
75
+ export * from './uma';
package/dist/index.js CHANGED
@@ -78,6 +78,8 @@ __exportStar(require("./passkey-sign-in"), exports);
78
78
  __exportStar(require("./passkey-sign-up"), exports);
79
79
  // Check an emailed one-time code without using it up (sign-in, sign-up, step-up, email verification).
80
80
  __exportStar(require("./email-code-check"), exports);
81
+ // SRP-6a sign-in (RFC 5054, 3072-bit group, SHA-256): the password never leaves the browser.
82
+ __exportStar(require("./srp"), exports);
81
83
  __exportStar(require("./step-up"), exports);
82
84
  __exportStar(require("./telegram"), exports);
83
85
  __exportStar(require("./siwe"), exports);
@@ -85,6 +87,8 @@ __exportStar(require("./telemetry"), exports);
85
87
  __exportStar(require("./reauth"), exports);
86
88
  // End-user API key self-service (`/v1/client/me/api_keys`).
87
89
  __exportStar(require("./api-keys"), exports);
90
+ // The apps a user authorized, with the OpenID Grant Management grants each holds.
91
+ __exportStar(require("./authorized-apps"), exports);
88
92
  __exportStar(require("./device-authorization"), exports);
89
93
  __exportStar(require("./app-launcher"), exports);
90
94
  __exportStar(require("./organizations"), exports);
@@ -98,6 +102,8 @@ __exportStar(require("./account-hints"), exports);
98
102
  __exportStar(require("./custom-challenge"), exports);
99
103
  // Identity verification (document and selfie) through the app's verification service.
100
104
  __exportStar(require("./identity-verification"), exports);
105
+ // Identity governance: request access, approve, review, delegate.
106
+ __exportStar(require("./iga"), exports);
101
107
  // Self-service profile update (incl. user-editable identity traits).
102
108
  __exportStar(require("./profile"), exports);
103
109
  __exportStar(require("./connect"), exports);
@@ -143,4 +149,5 @@ __exportStar(require("./delegated-ui"), exports);
143
149
  __exportStar(require("./external-passkeys"), exports);
144
150
  // Wallet-side helpers for verifiable credentials (receive an offer, present an SD-JWT VC).
145
151
  __exportStar(require("./credentials"), exports);
152
+ __exportStar(require("./uma"), exports);
146
153
  //# 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":";;;;;;;;;;;;;;;;;AAAA,6EAA6E;AAC7E,2CAAyB;AACzB,6CAA2B;AAC3B,yDAAyD;AACzD,kDAAgC;AAChC,sFAAsF;AACtF,mDAAiC;AACjC,gDAA8B;AAC9B,iDAA+B;AAC/B,4CAA0B;AAC1B,iDAA+B;AAC/B,kDAAgC;AAChC,uEAAuE;AACvE,2CAAyB;AACzB,6CAA2B;AAC3B,qFAAqF;AACrF,kDAAgC;AAChC,yCAAuB;AACvB,uEAAuE;AACvE,6CAA2B;AAC3B,mGAAmG;AACnG,2DAAyC;AACzC,4GAA4G;AAC5G,sDAAoC;AACpC,+CAA6B;AAC7B,+EAA+E;AAC/E,6CAA2B;AAC3B,8DAA4C;AAC5C,gGAAgG;AAChG,6CAAgJ;AAAvI,gHAAA,iBAAiB,OAAA;AAAE,8GAAA,eAAe,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,6GAAA,cAAc,OAAA;AAClG,qDAW2B;AAVzB,oHAAA,iBAAiB,OAAA;AACjB,2HAAA,wBAAwB,OAAA;AACxB,oHAAA,iBAAiB,OAAA;AACjB,gHAAA,aAAa,OAAA;AACb,wHAAA,qBAAqB,OAAA;AACrB,uHAAA,oBAAoB,OAAA;AAMtB,iEAAiE;AACjE,iDAA+B;AAC/B,4CAA0B;AAC1B,yFAAyF;AACzF,oDAAkC;AAClC,2CAAyB;AACzB,mDAAiC;AACjC,4CAA0B;AAC1B,2FAA2F;AAC3F,gDAA8B;AAC9B,+CAA6B;AAC7B,0GAA0G;AAC1G,mDAAiC;AACjC,iFAAiF;AACjF,gDAA8B;AAC9B,uFAAuF;AACvF,oDAAkC;AAClC,4EAA4E;AAC5E,oDAAkC;AAClC,sGAAsG;AACtG,qDAAmC;AACnC,4CAA0B;AAC1B,6CAA2B;AAC3B,yCAAuB;AACvB,8CAA4B;AAC5B,2CAAyB;AACzB,4DAA4D;AAC5D,6CAA2B;AAC3B,yDAAuC;AACvC,iDAA+B;AAC/B,kDAAgC;AAChC,uDAAqC;AACrC,4CAA0B;AAC1B,8CAA4B;AAC5B,kDAAgC;AAChC,oDAAkC;AAClC,+DAA+D;AAC/D,kDAAgC;AAChC,qDAAmC;AACnC,sFAAsF;AACtF,0DAAwC;AACxC,qEAAqE;AACrE,4CAA0B;AAC1B,4CAA0B;AAC1B,gDAA8B;AAC9B,mDAAiC;AACjC,kDAAgC;AAChC,gGAAgG;AAChG,uDAAqC;AACrC,+DAA6C;AAC7C,sDAAsD;AACtD,wDAAsC;AACtC,+EAA+E;AAC/E,oDAAkC;AAClC,+EAA+E;AAC/E,2EAA2E;AAC3E,4CAA0B;AAC1B,kFAAkF;AAClF,mDAAiC;AACjC,4FAA4F;AAC5F,kDAAgC;AAChC,kFAAkF;AAClF,yEAAyE;AACzE,oEAAoE;AACpE,uDAAqC;AACrC,sDAAoC;AACpC,uEAAuE;AACvE,gDAA8B;AAC9B,0EAA0E;AAC1E,4EAA4E;AAC5E,0CAa0B;AARxB,iGAAA,QAAQ,OAAA;AACR,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AACjB,uGAAA,cAAc,OAAA;AACd,yGAAA,gBAAgB,OAAA;AAChB,+GAAA,sBAAsB,OAAA;AACtB,kGAAA,SAAS,OAAA;AACT,wGAAA,eAAe,OAAA;AAEjB,qDAAmC;AAEnC,yGAAyG;AACzG,iDAA+B;AAE/B,kFAAkF;AAClF,sDAAoC;AAEpC,2FAA2F;AAC3F,gDAA8B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,6EAA6E;AAC7E,2CAAyB;AACzB,6CAA2B;AAC3B,yDAAyD;AACzD,kDAAgC;AAChC,sFAAsF;AACtF,mDAAiC;AACjC,gDAA8B;AAC9B,iDAA+B;AAC/B,4CAA0B;AAC1B,iDAA+B;AAC/B,kDAAgC;AAChC,uEAAuE;AACvE,2CAAyB;AACzB,6CAA2B;AAC3B,qFAAqF;AACrF,kDAAgC;AAChC,yCAAuB;AACvB,uEAAuE;AACvE,6CAA2B;AAC3B,mGAAmG;AACnG,2DAAyC;AACzC,4GAA4G;AAC5G,sDAAoC;AACpC,+CAA6B;AAC7B,+EAA+E;AAC/E,6CAA2B;AAC3B,8DAA4C;AAC5C,gGAAgG;AAChG,6CAAgJ;AAAvI,gHAAA,iBAAiB,OAAA;AAAE,8GAAA,eAAe,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AAAE,6GAAA,cAAc,OAAA;AAAE,6GAAA,cAAc,OAAA;AAClG,qDAW2B;AAVzB,oHAAA,iBAAiB,OAAA;AACjB,2HAAA,wBAAwB,OAAA;AACxB,oHAAA,iBAAiB,OAAA;AACjB,gHAAA,aAAa,OAAA;AACb,wHAAA,qBAAqB,OAAA;AACrB,uHAAA,oBAAoB,OAAA;AAMtB,iEAAiE;AACjE,iDAA+B;AAC/B,4CAA0B;AAC1B,yFAAyF;AACzF,oDAAkC;AAClC,2CAAyB;AACzB,mDAAiC;AACjC,4CAA0B;AAC1B,2FAA2F;AAC3F,gDAA8B;AAC9B,+CAA6B;AAC7B,0GAA0G;AAC1G,mDAAiC;AACjC,iFAAiF;AACjF,gDAA8B;AAC9B,uFAAuF;AACvF,oDAAkC;AAClC,4EAA4E;AAC5E,oDAAkC;AAClC,sGAAsG;AACtG,qDAAmC;AACnC,6FAA6F;AAC7F,wCAAsB;AACtB,4CAA0B;AAC1B,6CAA2B;AAC3B,yCAAuB;AACvB,8CAA4B;AAC5B,2CAAyB;AACzB,4DAA4D;AAC5D,6CAA2B;AAC3B,kFAAkF;AAClF,oDAAkC;AAClC,yDAAuC;AACvC,iDAA+B;AAC/B,kDAAgC;AAChC,uDAAqC;AACrC,4CAA0B;AAC1B,8CAA4B;AAC5B,kDAAgC;AAChC,oDAAkC;AAClC,+DAA+D;AAC/D,kDAAgC;AAChC,qDAAmC;AACnC,sFAAsF;AACtF,0DAAwC;AACxC,kEAAkE;AAClE,wCAAsB;AACtB,qEAAqE;AACrE,4CAA0B;AAC1B,4CAA0B;AAC1B,gDAA8B;AAC9B,mDAAiC;AACjC,kDAAgC;AAChC,gGAAgG;AAChG,uDAAqC;AACrC,+DAA6C;AAC7C,sDAAsD;AACtD,wDAAsC;AACtC,+EAA+E;AAC/E,oDAAkC;AAClC,+EAA+E;AAC/E,2EAA2E;AAC3E,4CAA0B;AAC1B,kFAAkF;AAClF,mDAAiC;AACjC,4FAA4F;AAC5F,kDAAgC;AAChC,kFAAkF;AAClF,yEAAyE;AACzE,oEAAoE;AACpE,uDAAqC;AACrC,sDAAoC;AACpC,uEAAuE;AACvE,gDAA8B;AAC9B,0EAA0E;AAC1E,4EAA4E;AAC5E,0CAa0B;AARxB,iGAAA,QAAQ,OAAA;AACR,sGAAA,aAAa,OAAA;AACb,0GAAA,iBAAiB,OAAA;AACjB,uGAAA,cAAc,OAAA;AACd,yGAAA,gBAAgB,OAAA;AAChB,+GAAA,sBAAsB,OAAA;AACtB,kGAAA,SAAS,OAAA;AACT,wGAAA,eAAe,OAAA;AAEjB,qDAAmC;AAEnC,yGAAyG;AACzG,iDAA+B;AAE/B,kFAAkF;AAClF,sDAAoC;AAEpC,2FAA2F;AAC3F,gDAA8B;AAC9B,wCAAsB"}
package/dist/srp.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * SRP-6a sign-in: prove knowledge of the password without sending it.
3
+ *
4
+ * Uses RFC 5054's 3072-bit group with SHA-256 (the server publishes the same
5
+ * parameters), on WebCrypto and BigInt, so it runs in any current browser and
6
+ * Node. The flow on an existing sign-in attempt:
7
+ *
8
+ * srp_challenge -> salt, B, and the identity to hash in
9
+ * srp_verify -> M1 (the client proof); the server answers with M2
10
+ *
11
+ * and the helper checks M2, so a server that does not know the verifier cannot
12
+ * pass as Atlas. SRP does not replace TLS, and a passkey is a stronger
13
+ * sign-in; use this for apps that already speak SRP (Cognito migrations) or
14
+ * that must keep the password out of the request body.
15
+ */
16
+ import type { FapiClient, FapiResponse } from './fapi';
17
+ export interface SrpClientProof {
18
+ /** Public value A, hex, for the challenge request. */
19
+ A: string;
20
+ /** Finish with the server's answer: the client proof M1 and the server proof M2 expected back (both hex). */
21
+ respond(challenge: {
22
+ salt: string;
23
+ srp_b: string;
24
+ user_id_for_srp: string;
25
+ }, password: string): Promise<{
26
+ M1: string;
27
+ M2: string;
28
+ }>;
29
+ }
30
+ /** Start the client side of an exchange. `privateKey` is for tests; leave it unset. */
31
+ export declare function srpClientStart(privateKey?: bigint): SrpClientProof;
32
+ export declare const SRP_CHALLENGE_PATH: (attemptId: string) => string;
33
+ export declare const SRP_VERIFY_PATH: (attemptId: string) => string;
34
+ export interface SrpSignInOptions {
35
+ identifier: string;
36
+ password: string;
37
+ /** Continue an attempt that already has its identifier; otherwise one is started. */
38
+ attemptId?: string;
39
+ /**
40
+ * When SRP does not work (the account has no verifier yet, for example one migrated from
41
+ * another provider), try an ordinary password sign-in on the same attempt, which also
42
+ * sets up the verifier for next time. Default false.
43
+ */
44
+ fallbackToPassword?: boolean;
45
+ /** Fixed client private value, for tests only. */
46
+ privateKey?: bigint;
47
+ }
48
+ export type SrpSignInResult = FapiResponse<Record<string, unknown>> & {
49
+ /** True when the server proved it knew the verifier (its M2 matched). */
50
+ serverVerified: boolean;
51
+ attemptId: string | null;
52
+ method: 'srp' | 'password';
53
+ };
54
+ /** Sign in with SRP. On success `data` is the attempt view (with `ticket` when complete). */
55
+ export declare function signInWithSrp(client: FapiClient, opts: SrpSignInOptions): Promise<SrpSignInResult>;
package/dist/srp.js ADDED
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SRP_VERIFY_PATH = exports.SRP_CHALLENGE_PATH = void 0;
4
+ exports.srpClientStart = srpClientStart;
5
+ exports.signInWithSrp = signInWithSrp;
6
+ const N_HEX = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF';
7
+ const N = BigInt('0x' + N_HEX);
8
+ // BigInt() calls, not literals: the embed bundle targets ES2019 syntax.
9
+ const ZERO = BigInt(0);
10
+ const ONE = BigInt(1);
11
+ const G = BigInt(5);
12
+ const N_LEN = N_HEX.length / 2;
13
+ const enc = new TextEncoder();
14
+ const toHex = (b) => Array.from(b, (v) => v.toString(16).padStart(2, '0')).join('');
15
+ const fromHex = (h) => Uint8Array.from((h.length % 2 ? '0' + h : h).match(/../g) ?? [], (x) => parseInt(x, 16));
16
+ const big = (b) => (b.length ? BigInt('0x' + toHex(b)) : ZERO);
17
+ const bytes = (n) => fromHex(n.toString(16));
18
+ const pad = (n) => {
19
+ const b = bytes(n);
20
+ const out = new Uint8Array(Math.max(N_LEN, b.length));
21
+ out.set(b, out.length - b.length);
22
+ return out;
23
+ };
24
+ const concat = (...parts) => {
25
+ const out = new Uint8Array(parts.reduce((s, p) => s + p.length, 0));
26
+ let o = 0;
27
+ for (const p of parts) {
28
+ out.set(p, o);
29
+ o += p.length;
30
+ }
31
+ return out;
32
+ };
33
+ const sha256 = async (...parts) => new Uint8Array(await crypto.subtle.digest('SHA-256', concat(...parts)));
34
+ function modPow(base, exp, mod) {
35
+ let result = ONE;
36
+ let b = ((base % mod) + mod) % mod;
37
+ for (let e = exp; e > ZERO; e >>= ONE) {
38
+ if (e & ONE)
39
+ result = (result * b) % mod;
40
+ b = (b * b) % mod;
41
+ }
42
+ return result;
43
+ }
44
+ /** Start the client side of an exchange. `privateKey` is for tests; leave it unset. */
45
+ function srpClientStart(privateKey) {
46
+ const a = privateKey ?? big(crypto.getRandomValues(new Uint8Array(64)));
47
+ const A = modPow(G, a, N);
48
+ return {
49
+ A: A.toString(16),
50
+ async respond(ch, password) {
51
+ const B = BigInt('0x' + ch.srp_b);
52
+ if (B % N === ZERO)
53
+ throw new Error('The server sent an invalid SRP value.');
54
+ const k = big(await sha256(bytes(N), pad(G)));
55
+ const u = big(await sha256(pad(A), pad(B)));
56
+ const inner = await sha256(enc.encode(`${ch.user_id_for_srp}:${password}`));
57
+ const x = big(await sha256(fromHex(ch.salt), inner));
58
+ const base = (((B - k * modPow(G, x, N)) % N) + N) % N;
59
+ const S = modPow(base, a + u * x, N);
60
+ const K = await sha256(bytes(S));
61
+ const hn = await sha256(bytes(N));
62
+ const hg = await sha256(bytes(G));
63
+ const xored = hn.map((v, i) => v ^ hg[i]);
64
+ const M1 = await sha256(xored, await sha256(enc.encode(ch.user_id_for_srp)), fromHex(ch.salt), pad(A), pad(B), K);
65
+ const M2 = await sha256(pad(A), M1, K);
66
+ return { M1: toHex(M1), M2: toHex(M2) };
67
+ },
68
+ };
69
+ }
70
+ const SRP_CHALLENGE_PATH = (attemptId) => `/v1/client/sign_ins/${encodeURIComponent(attemptId)}/srp_challenge`;
71
+ exports.SRP_CHALLENGE_PATH = SRP_CHALLENGE_PATH;
72
+ const SRP_VERIFY_PATH = (attemptId) => `/v1/client/sign_ins/${encodeURIComponent(attemptId)}/srp_verify`;
73
+ exports.SRP_VERIFY_PATH = SRP_VERIFY_PATH;
74
+ const fail = (status, message) => ({
75
+ ok: false,
76
+ status,
77
+ data: null,
78
+ errors: [{ code: 'SRP_FAILED', message }],
79
+ serverVerified: false,
80
+ attemptId: null,
81
+ method: 'srp',
82
+ });
83
+ /** Sign in with SRP. On success `data` is the attempt view (with `ticket` when complete). */
84
+ async function signInWithSrp(client, opts) {
85
+ let attemptId = opts.attemptId ?? null;
86
+ if (!attemptId) {
87
+ const start = await client.post('/v1/client/sign_ins', { identifier: opts.identifier });
88
+ if (!start.ok || !start.data)
89
+ return { ...start, serverVerified: false, attemptId: null, method: 'srp' };
90
+ attemptId = start.data.id;
91
+ }
92
+ const passwordFallback = async () => {
93
+ const res = await client.post(`/v1/client/sign_ins/${encodeURIComponent(attemptId)}/attempt_first_factor`, {
94
+ strategy: 'password',
95
+ password: opts.password,
96
+ });
97
+ return { ...res, serverVerified: false, attemptId, method: 'password' };
98
+ };
99
+ const proof = srpClientStart(opts.privateKey);
100
+ const challenge = await client.post((0, exports.SRP_CHALLENGE_PATH)(attemptId), { srp_a: proof.A });
101
+ if (!challenge.ok || !challenge.data)
102
+ return opts.fallbackToPassword && challenge.status === 422 ? passwordFallback() : { ...challenge, serverVerified: false, attemptId, method: 'srp' };
103
+ let answer;
104
+ try {
105
+ answer = await proof.respond(challenge.data, opts.password);
106
+ }
107
+ catch (e) {
108
+ return fail(400, e.message);
109
+ }
110
+ const verified = await client.post((0, exports.SRP_VERIFY_PATH)(attemptId), { srp_session: challenge.data.srp_session, srp_m1: answer.M1 });
111
+ if (!verified.ok) {
112
+ // The attempt has used its failure budget on this try; the fallback is a second, ordinary attempt.
113
+ return opts.fallbackToPassword ? passwordFallback() : { ...verified, serverVerified: false, attemptId, method: 'srp' };
114
+ }
115
+ const serverVerified = verified.data?.srp_m2 === answer.M2;
116
+ if (!serverVerified)
117
+ return { ...fail(400, 'The server did not prove it knows the verifier.'), attemptId };
118
+ return { ...verified, serverVerified, attemptId, method: 'srp' };
119
+ }
120
+ //# sourceMappingURL=srp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"srp.js","sourceRoot":"","sources":["../src/srp.ts"],"names":[],"mappings":";;;AAkEA,wCAuBC;AAsCD,sCAiCC;AA/ID,MAAM,KAAK,GACT,kwBAAkwB,CAAC;AACrwB,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;AAC/B,wEAAwE;AACxE,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AACvB,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AACtB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;AACpB,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AAE/B,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;AAC9B,MAAM,KAAK,GAAG,CAAC,CAAa,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAChG,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AACxH,MAAM,GAAG,GAAG,CAAC,CAAa,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC3E,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AACrD,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE;IACxB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACnB,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACtD,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AACF,MAAM,MAAM,GAAG,CAAC,GAAG,KAAmB,EAAE,EAAE;IACxC,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACd,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AACF,MAAM,MAAM,GAAG,KAAK,EAAE,GAAG,KAAmB,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,KAAK,CAAiB,CAAC,CAAC,CAAC;AAEzI,SAAS,MAAM,CAAC,IAAY,EAAE,GAAW,EAAE,GAAW;IACpD,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC;QACtC,IAAI,CAAC,GAAG,GAAG;YAAE,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;QACzC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IACpB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AASD,uFAAuF;AACvF,SAAgB,cAAc,CAAC,UAAmB;IAChD,MAAM,CAAC,GAAG,UAAU,IAAI,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,OAAO;QACL,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjB,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,QAAQ;YACxB,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC7E,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;YAC5E,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;YACrD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YACvD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YACrC,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAE,CAAC,CAAC;YAC3C,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAClH,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YACvC,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QAC1C,CAAC;KACF,CAAC;AACJ,CAAC;AAEM,MAAM,kBAAkB,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,uBAAuB,kBAAkB,CAAC,SAAS,CAAC,gBAAgB,CAAC;AAAjH,QAAA,kBAAkB,sBAA+F;AACvH,MAAM,eAAe,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,uBAAuB,kBAAkB,CAAC,SAAS,CAAC,aAAa,CAAC;AAA3G,QAAA,eAAe,mBAA4F;AAwBxH,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,OAAe,EAAmB,EAAE,CAAC,CAAC;IAClE,EAAE,EAAE,KAAK;IACT,MAAM;IACN,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;IACzC,cAAc,EAAE,KAAK;IACrB,SAAS,EAAE,IAAI;IACf,MAAM,EAAE,KAAK;CACd,CAAC,CAAC;AAEH,6FAA6F;AACtF,KAAK,UAAU,aAAa,CAAC,MAAkB,EAAE,IAAsB;IAC5E,IAAI,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC;IACvC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAiB,qBAAqB,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QACxG,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YAAE,OAAO,EAAE,GAAG,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAqB,CAAC;QAC5H,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,gBAAgB,GAAG,KAAK,IAA8B,EAAE;QAC5D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAA0B,uBAAuB,kBAAkB,CAAC,SAAU,CAAC,uBAAuB,EAAE;YACnI,QAAQ,EAAE,UAAU;YACpB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;QACH,OAAO,EAAE,GAAG,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC1E,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,IAAI,CAAgF,IAAA,0BAAkB,EAAC,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IACtK,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC,kBAAkB,IAAI,SAAS,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAqB,CAAC;IAE7M,IAAI,MAAkC,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,IAAI,CAAC,GAAG,EAAG,CAAW,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAA0B,IAAA,uBAAe,EAAC,SAAS,CAAC,EAAE,EAAE,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IACxJ,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,mGAAmG;QACnG,OAAO,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAE,EAAE,GAAG,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAsB,CAAC;IAC9I,CAAC;IACD,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;IAC3D,IAAI,CAAC,cAAc;QAAE,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,iDAAiD,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3G,OAAO,EAAE,GAAG,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACnE,CAAC"}
package/dist/uma.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ import type { FapiClient } from './fapi';
2
+ /**
3
+ * User-Managed Access, from the two browser-side seats.
4
+ *
5
+ * The RESOURCE OWNER (signed in, cookie-authenticated through the {@link FapiClient}): list what they own and who
6
+ * it is shared with, share and stop sharing, and answer access requests (`/v1/client/me/uma/*`).
7
+ *
8
+ * The CLIENT acting for a requesting party: build the claims-gathering URL for a `need_info` answer that carries
9
+ * `redirect_user`, and read the ticket / error from the redirect back.
10
+ */
11
+ export interface UmaPolicy {
12
+ object: 'uma_policy';
13
+ id: string;
14
+ resource_id: string;
15
+ subject: {
16
+ type: 'user' | 'group' | 'org';
17
+ id: string;
18
+ };
19
+ scopes: string[];
20
+ created_at: number;
21
+ }
22
+ export interface UmaOwnedResource {
23
+ object: 'uma_resource';
24
+ id: string;
25
+ name: string;
26
+ type: string | null;
27
+ uri: string | null;
28
+ resource_scopes: string[];
29
+ app: string | null;
30
+ policies: UmaPolicy[];
31
+ }
32
+ export interface UmaAccessRequest {
33
+ object: 'uma_access_request';
34
+ id: string;
35
+ resource_id: string;
36
+ resource_name?: string;
37
+ requester_user_id: string;
38
+ /** The requester's email address. */
39
+ requester?: string | null;
40
+ scopes: string[];
41
+ status: 'pending' | 'approved' | 'denied';
42
+ created_at: number;
43
+ decided_at: number | null;
44
+ }
45
+ /** A refused request; `code` is the server's stable error code. */
46
+ export declare class UmaError extends Error {
47
+ readonly status: number;
48
+ readonly code: string;
49
+ constructor(status: number, code: string, message: string);
50
+ }
51
+ /** The resources the signed-in user owns, with who each is shared with. */
52
+ export declare function listUmaResources(client: FapiClient): Promise<UmaOwnedResource[]>;
53
+ /** Share a resource with a person (verified `email`) or a `subject` (user, group, org). Replaces an earlier share to the same subject. */
54
+ export declare function shareUmaResource(client: FapiClient, resourceId: string, target: {
55
+ email: string;
56
+ } | {
57
+ subject: {
58
+ type: 'user' | 'group' | 'org';
59
+ id: string;
60
+ };
61
+ }, scopes: string[]): Promise<UmaPolicy>;
62
+ export declare function unshareUmaResource(client: FapiClient, resourceId: string, subject: {
63
+ type: string;
64
+ id: string;
65
+ }): Promise<void>;
66
+ /** Access requests for the user's resources (the owner-approval queue). */
67
+ export declare function listUmaAccessRequests(client: FapiClient, status?: UmaAccessRequest['status']): Promise<UmaAccessRequest[]>;
68
+ /** Approve (optionally narrowing `scopes`) or deny a pending request. A request is decided once. */
69
+ export declare function decideUmaAccessRequest(client: FapiClient, requestId: string, decision: 'approve' | 'deny', scopes?: string[]): Promise<UmaAccessRequest>;
70
+ /**
71
+ * The URL to send the requesting party to for interactive claims gathering. `redirectUser` is the `redirect_user`
72
+ * from the `need_info` answer; `ticket` is that answer's (rotated) ticket. `claimsRedirectUri` must be one of the
73
+ * client's registered claims redirect URIs.
74
+ */
75
+ export declare function umaClaimsUrl(redirectUser: string, params: {
76
+ clientId: string;
77
+ ticket: string;
78
+ claimsRedirectUri?: string;
79
+ state?: string;
80
+ }): string;
81
+ /** Read the redirect back from claims gathering: a new `ticket`, or an `error` (the person cancelled). */
82
+ export declare function parseUmaClaimsRedirect(redirectUrl: string): {
83
+ ticket?: string;
84
+ error?: string;
85
+ state?: string;
86
+ };
package/dist/uma.js ADDED
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UmaError = void 0;
4
+ exports.listUmaResources = listUmaResources;
5
+ exports.shareUmaResource = shareUmaResource;
6
+ exports.unshareUmaResource = unshareUmaResource;
7
+ exports.listUmaAccessRequests = listUmaAccessRequests;
8
+ exports.decideUmaAccessRequest = decideUmaAccessRequest;
9
+ exports.umaClaimsUrl = umaClaimsUrl;
10
+ exports.parseUmaClaimsRedirect = parseUmaClaimsRedirect;
11
+ /** A refused request; `code` is the server's stable error code. */
12
+ class UmaError extends Error {
13
+ status;
14
+ code;
15
+ constructor(status, code, message) {
16
+ super(message);
17
+ this.name = 'UmaError';
18
+ this.status = status;
19
+ this.code = code;
20
+ }
21
+ }
22
+ exports.UmaError = UmaError;
23
+ async function call(client, path, init) {
24
+ const res = await client.request(path, init);
25
+ if (!res.ok) {
26
+ const first = res.errors[0];
27
+ throw new UmaError(res.status, first?.code ?? 'UNKNOWN', first?.message ?? 'The request failed.');
28
+ }
29
+ return res.data;
30
+ }
31
+ const json = (method, body) => ({ method, body: JSON.stringify(body), headers: { 'content-type': 'application/json' } });
32
+ const enc = encodeURIComponent;
33
+ /** The resources the signed-in user owns, with who each is shared with. */
34
+ async function listUmaResources(client) {
35
+ return (await call(client, '/v1/client/me/uma/resources', { method: 'GET' })).data ?? [];
36
+ }
37
+ /** Share a resource with a person (verified `email`) or a `subject` (user, group, org). Replaces an earlier share to the same subject. */
38
+ function shareUmaResource(client, resourceId, target, scopes) {
39
+ return call(client, `/v1/client/me/uma/resources/${enc(resourceId)}/policies`, json('PUT', { ...target, scopes }));
40
+ }
41
+ async function unshareUmaResource(client, resourceId, subject) {
42
+ await call(client, `/v1/client/me/uma/resources/${enc(resourceId)}/policies/${enc(subject.type)}/${enc(subject.id)}`, { method: 'DELETE' });
43
+ }
44
+ /** Access requests for the user's resources (the owner-approval queue). */
45
+ async function listUmaAccessRequests(client, status) {
46
+ const q = status ? `?status=${enc(status)}` : '';
47
+ return (await call(client, `/v1/client/me/uma/requests${q}`, { method: 'GET' })).data ?? [];
48
+ }
49
+ /** Approve (optionally narrowing `scopes`) or deny a pending request. A request is decided once. */
50
+ function decideUmaAccessRequest(client, requestId, decision, scopes) {
51
+ return call(client, `/v1/client/me/uma/requests/${enc(requestId)}/decision`, json('POST', { decision, ...(scopes ? { scopes } : {}) }));
52
+ }
53
+ /**
54
+ * The URL to send the requesting party to for interactive claims gathering. `redirectUser` is the `redirect_user`
55
+ * from the `need_info` answer; `ticket` is that answer's (rotated) ticket. `claimsRedirectUri` must be one of the
56
+ * client's registered claims redirect URIs.
57
+ */
58
+ function umaClaimsUrl(redirectUser, params) {
59
+ const url = new URL(redirectUser);
60
+ url.searchParams.set('client_id', params.clientId);
61
+ url.searchParams.set('ticket', params.ticket);
62
+ if (params.claimsRedirectUri)
63
+ url.searchParams.set('claims_redirect_uri', params.claimsRedirectUri);
64
+ if (params.state)
65
+ url.searchParams.set('state', params.state);
66
+ return url.toString();
67
+ }
68
+ /** Read the redirect back from claims gathering: a new `ticket`, or an `error` (the person cancelled). */
69
+ function parseUmaClaimsRedirect(redirectUrl) {
70
+ const p = new URL(redirectUrl).searchParams;
71
+ return { ticket: p.get('ticket') ?? undefined, error: p.get('error') ?? undefined, state: p.get('state') ?? undefined };
72
+ }
73
+ //# sourceMappingURL=uma.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uma.js","sourceRoot":"","sources":["../src/uma.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * package.json at runtime) so the bundle stays dependency-free and tests stay
5
5
  * deterministic; `version.test.ts` fails when it drifts from package.json.
6
6
  */
7
- export declare const ATLAS_JS_VERSION = "0.24.0";
7
+ export declare const ATLAS_JS_VERSION = "0.25.0";
package/dist/version.js CHANGED
@@ -7,5 +7,5 @@ exports.ATLAS_JS_VERSION = void 0;
7
7
  * package.json at runtime) so the bundle stays dependency-free and tests stay
8
8
  * deterministic; `version.test.ts` fails when it drifts from package.json.
9
9
  */
10
- exports.ATLAS_JS_VERSION = '0.24.0';
10
+ exports.ATLAS_JS_VERSION = '0.25.0';
11
11
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlasauth/js",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "exports": {
@@ -20,7 +20,7 @@
20
20
  "vitest": "^2.1.4"
21
21
  },
22
22
  "dependencies": {
23
- "@atlasauth/authz": "0.2.0"
23
+ "@atlasauth/authz": "0.3.0"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"