@authyon/auth 0.2.0-beta.12 → 0.2.0-beta.15
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 +23 -0
- package/dist/{ability-B1TiHFWa.d.cts → ability-5_xXXbDF.d.cts} +87 -1
- package/dist/{ability-B1TiHFWa.d.ts → ability-5_xXXbDF.d.ts} +87 -1
- package/dist/index.cjs +81 -24
- package/dist/index.d.cts +47 -22
- package/dist/index.d.ts +47 -22
- package/dist/index.js +75 -18
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -273,6 +273,29 @@ Métodos de sessão/auth ficam soltos no client; os que giram em torno de um rec
|
|
|
273
273
|
| `sso.startUrl(provider, params)` | monta a URL de `GET /auth/sso/{provider}/start` (não faz a chamada — navegue até ela) |
|
|
274
274
|
| `sso.exchange(code)` | `POST /auth/sso/exchange` |
|
|
275
275
|
|
|
276
|
+
### `authyon.security` (aprovação com OTP/passkey)
|
|
277
|
+
|
|
278
|
+
`security.approvals`: o cliente aprova o que o seu backend pediu
|
|
279
|
+
(`@authyon/server` → `security.approvals.create`, com um `payload` livre) usando o código
|
|
280
|
+
do app autenticador ou a passkey. Para só validar um código, use `security.otp.check` no
|
|
281
|
+
`@authyon/server`. Guia completo: [`docs/security-otp-approvals.md`](../../docs/security-otp-approvals.md).
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
const pending = await authyon.security.approvals.get(approvalId);
|
|
285
|
+
// mostre pending.payload ao cliente
|
|
286
|
+
await authyon.security.approvals.confirm(approvalId, {
|
|
287
|
+
method: "authenticator",
|
|
288
|
+
code: "123456",
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
| Método | Endpoint |
|
|
293
|
+
| ---------------------------------------- | ------------------------------------------------- |
|
|
294
|
+
| `security.approvals.get(id)` | `GET /auth/authorizations/{id}` |
|
|
295
|
+
| `security.approvals.webauthnOptions(id)` | `POST /auth/authorizations/{id}/webauthn/options` |
|
|
296
|
+
| `security.approvals.confirm(id, input?)` | `POST /auth/authorizations/{id}/confirm` |
|
|
297
|
+
| `security.approvals.reject(id)` | `POST /auth/authorizations/{id}/reject` |
|
|
298
|
+
|
|
276
299
|
## Invalidação de token
|
|
277
300
|
|
|
278
301
|
- **Sessão atual**: `logout()` revoga o refresh token atual; `logout({ everywhere: true })` revoga todos os refresh tokens do usuário.
|
|
@@ -1,3 +1,58 @@
|
|
|
1
|
+
/** Lifecycle of an approval. */
|
|
2
|
+
type ApprovalStatus = "pending" | "approved" | "denied" | "consumed" | "expired";
|
|
3
|
+
/**
|
|
4
|
+
* Free-form JSON object describing what the customer approves (up to 16 KiB).
|
|
5
|
+
* The API stores it, shows it back to the customer and binds its canonical
|
|
6
|
+
* hash (keys sorted) to the approval.
|
|
7
|
+
*/
|
|
8
|
+
type ApprovalPayload = Record<string, unknown>;
|
|
9
|
+
/** Evidence of how the customer proved their identity when approving. */
|
|
10
|
+
interface ApprovalAssurance {
|
|
11
|
+
/** `urn:authyon:loa:3` (passkey) or `urn:authyon:loa:2` (authenticator code). */
|
|
12
|
+
acr: string;
|
|
13
|
+
/** Authentication methods, e.g. `["pwd", "otp"]` or `["pwd", "webauthn"]`. */
|
|
14
|
+
amr: string[];
|
|
15
|
+
/** When the second factor was verified (ISO 8601). */
|
|
16
|
+
authTime: string;
|
|
17
|
+
}
|
|
18
|
+
/** A request for the customer to approve something with a second factor. */
|
|
19
|
+
interface Approval {
|
|
20
|
+
id: string;
|
|
21
|
+
status: ApprovalStatus;
|
|
22
|
+
subjectId: string;
|
|
23
|
+
tenantId?: string | null;
|
|
24
|
+
/** The payload given to `create()`, with keys in canonical order. */
|
|
25
|
+
payload: ApprovalPayload;
|
|
26
|
+
/** SHA-256 (hex) of the canonical payload. */
|
|
27
|
+
payloadHash: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
expiresAt: string;
|
|
30
|
+
decidedAt?: string | null;
|
|
31
|
+
consumedAt?: string | null;
|
|
32
|
+
/** Present once approved. */
|
|
33
|
+
assurance?: ApprovalAssurance | null;
|
|
34
|
+
}
|
|
35
|
+
/** Second factor sent with `confirm()`. */
|
|
36
|
+
type ConfirmApprovalInput = {
|
|
37
|
+
method: "authenticator";
|
|
38
|
+
/** Six-digit code from the customer's authenticator app. */
|
|
39
|
+
code: string;
|
|
40
|
+
} | {
|
|
41
|
+
method: "webauthn";
|
|
42
|
+
/** Assertion for the options returned by `webauthnOptions()`. */
|
|
43
|
+
webAuthn: {
|
|
44
|
+
ceremonyToken: string;
|
|
45
|
+
/** JSON-serialized `PublicKeyCredential` from `navigator.credentials.get()`. */
|
|
46
|
+
assertionJson: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
/** Passkey assertion options for approving one approval. */
|
|
50
|
+
interface ApprovalWebAuthnOptions {
|
|
51
|
+
ceremonyToken: string;
|
|
52
|
+
/** JSON `PublicKeyCredentialRequestOptions` to pass to `navigator.credentials.get()`. */
|
|
53
|
+
optionsJson: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
1
56
|
interface HttpAdapterRequest {
|
|
2
57
|
url: string;
|
|
3
58
|
method: string;
|
|
@@ -55,6 +110,30 @@ declare class LoggingHttpAdapter implements HttpAdapter {
|
|
|
55
110
|
private log;
|
|
56
111
|
}
|
|
57
112
|
|
|
113
|
+
/** Customer-side operations on an approval (`/auth/authorizations`). */
|
|
114
|
+
interface SubjectApprovals {
|
|
115
|
+
/** GET /auth/authorizations/{id} — the pending payload, to show before asking for the code. */
|
|
116
|
+
get(id: string): Promise<Approval>;
|
|
117
|
+
/** POST /auth/authorizations/{id}/webauthn/options — passkey options for approving it. */
|
|
118
|
+
webauthnOptions(id: string): Promise<ApprovalWebAuthnOptions>;
|
|
119
|
+
/**
|
|
120
|
+
* POST /auth/authorizations/{id}/confirm — approves it.
|
|
121
|
+
*
|
|
122
|
+
* Pass the authenticator code or passkey assertion to verify the second
|
|
123
|
+
* factor inline (recommended). Without `input`, the session itself must
|
|
124
|
+
* have used a passkey or authenticator code within the last 5 minutes,
|
|
125
|
+
* otherwise the API answers `step_up_required`.
|
|
126
|
+
*/
|
|
127
|
+
confirm(id: string, input?: ConfirmApprovalInput): Promise<Approval>;
|
|
128
|
+
/** POST /auth/authorizations/{id}/reject — the customer declines it. */
|
|
129
|
+
reject(id: string): Promise<Approval>;
|
|
130
|
+
}
|
|
131
|
+
/** The `security` namespace an end-user client exposes. */
|
|
132
|
+
interface SubjectSecurity {
|
|
133
|
+
/** Approve or reject what your backend asked the customer to confirm. */
|
|
134
|
+
readonly approvals: SubjectApprovals;
|
|
135
|
+
}
|
|
136
|
+
|
|
58
137
|
interface PaginationOptions {
|
|
59
138
|
skip?: number;
|
|
60
139
|
take?: number;
|
|
@@ -518,6 +597,13 @@ declare class AuthyonClient {
|
|
|
518
597
|
assertionStart: (challengeToken: string) => Promise<WebAuthnCeremonyStart>;
|
|
519
598
|
};
|
|
520
599
|
};
|
|
600
|
+
/**
|
|
601
|
+
* `security.approvals`: approve or reject what your backend asked the
|
|
602
|
+
* customer to confirm (`@authyon/server` → `security.approvals.create`).
|
|
603
|
+
* Show the payload with `get()`, then `confirm()` with the customer's
|
|
604
|
+
* authenticator code or passkey, or `reject()`.
|
|
605
|
+
*/
|
|
606
|
+
readonly security: SubjectSecurity;
|
|
521
607
|
/**
|
|
522
608
|
* POST /auth/introspect — lightweight token introspection (RFC 7662).
|
|
523
609
|
*
|
|
@@ -642,4 +728,4 @@ declare function hasPermissionGroup(source: AuthyonPermissionSource | readonly s
|
|
|
642
728
|
/** Converts Authyon's `subject:action` permission strings to authorization rules. */
|
|
643
729
|
declare function createAuthyonRules(source?: AuthyonPermissionSource, options?: AuthyonAbilityOptions): AbilityRule[];
|
|
644
730
|
|
|
645
|
-
export {
|
|
731
|
+
export { type TwoFactorMethod as $, AuthyonClient as A, type InviteMemberInput as B, type ConfirmApprovalInput as C, type LoginInput as D, type LoginResult as E, FetchHttpAdapter as F, type OrganizationMember as G, type HttpAdapter as H, type IntrospectResult as I, type PaginationOptions as J, type PermissionGroup as K, LoggingHttpAdapter as L, type Role as M, type SessionControllerOptions as N, type Organization as O, type Paged as P, type SessionInfo as Q, type RegisterInput as R, type Session as S, type TokenStorage as T, type SessionSnapshot as U, type SessionSnapshotListener as V, type SessionStatus as W, type SsoProvider as X, type SubjectApprovals as Y, type SubjectSecurity as Z, type TwoFactorChallenge as _, type HttpLoggerOptions as a, type TwoFactorStatus as a0, type User as a1, type ValidateResult as a2, type VerifyTwoFactorInput as a3, type WebAuthnAssertion as a4, type WebAuthnCeremonyStart as a5, type WebAuthnCredential as a6, createAuthyonAbility as a7, createAuthyonRules as a8, createClient as a9, hasPermission as aa, hasPermissionGroup as ab, type AbilityConditions as b, type AbilityEvent as c, type AbilityListener as d, type AbilityRule as e, type AbilitySubject as f, type Activity as g, type Approval as h, type ApprovalAssurance as i, type ApprovalPayload as j, type ApprovalStatus as k, type ApprovalWebAuthnOptions as l, type AuthEvent as m, type AuthState as n, type AuthStateListener as o, type AuthenticatorSetup as p, AuthyonAbility as q, AuthyonAbilityBuilder as r, type AuthyonAbilityOptions as s, type AuthyonClientOptions as t, type AuthyonPermissionSource as u, AuthyonSessionController as v, type CreateOrganizationInput as w, type HttpAdapterRequest as x, type HttpLogEvent as y, type HttpLogger as z };
|
|
@@ -1,3 +1,58 @@
|
|
|
1
|
+
/** Lifecycle of an approval. */
|
|
2
|
+
type ApprovalStatus = "pending" | "approved" | "denied" | "consumed" | "expired";
|
|
3
|
+
/**
|
|
4
|
+
* Free-form JSON object describing what the customer approves (up to 16 KiB).
|
|
5
|
+
* The API stores it, shows it back to the customer and binds its canonical
|
|
6
|
+
* hash (keys sorted) to the approval.
|
|
7
|
+
*/
|
|
8
|
+
type ApprovalPayload = Record<string, unknown>;
|
|
9
|
+
/** Evidence of how the customer proved their identity when approving. */
|
|
10
|
+
interface ApprovalAssurance {
|
|
11
|
+
/** `urn:authyon:loa:3` (passkey) or `urn:authyon:loa:2` (authenticator code). */
|
|
12
|
+
acr: string;
|
|
13
|
+
/** Authentication methods, e.g. `["pwd", "otp"]` or `["pwd", "webauthn"]`. */
|
|
14
|
+
amr: string[];
|
|
15
|
+
/** When the second factor was verified (ISO 8601). */
|
|
16
|
+
authTime: string;
|
|
17
|
+
}
|
|
18
|
+
/** A request for the customer to approve something with a second factor. */
|
|
19
|
+
interface Approval {
|
|
20
|
+
id: string;
|
|
21
|
+
status: ApprovalStatus;
|
|
22
|
+
subjectId: string;
|
|
23
|
+
tenantId?: string | null;
|
|
24
|
+
/** The payload given to `create()`, with keys in canonical order. */
|
|
25
|
+
payload: ApprovalPayload;
|
|
26
|
+
/** SHA-256 (hex) of the canonical payload. */
|
|
27
|
+
payloadHash: string;
|
|
28
|
+
createdAt: string;
|
|
29
|
+
expiresAt: string;
|
|
30
|
+
decidedAt?: string | null;
|
|
31
|
+
consumedAt?: string | null;
|
|
32
|
+
/** Present once approved. */
|
|
33
|
+
assurance?: ApprovalAssurance | null;
|
|
34
|
+
}
|
|
35
|
+
/** Second factor sent with `confirm()`. */
|
|
36
|
+
type ConfirmApprovalInput = {
|
|
37
|
+
method: "authenticator";
|
|
38
|
+
/** Six-digit code from the customer's authenticator app. */
|
|
39
|
+
code: string;
|
|
40
|
+
} | {
|
|
41
|
+
method: "webauthn";
|
|
42
|
+
/** Assertion for the options returned by `webauthnOptions()`. */
|
|
43
|
+
webAuthn: {
|
|
44
|
+
ceremonyToken: string;
|
|
45
|
+
/** JSON-serialized `PublicKeyCredential` from `navigator.credentials.get()`. */
|
|
46
|
+
assertionJson: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
/** Passkey assertion options for approving one approval. */
|
|
50
|
+
interface ApprovalWebAuthnOptions {
|
|
51
|
+
ceremonyToken: string;
|
|
52
|
+
/** JSON `PublicKeyCredentialRequestOptions` to pass to `navigator.credentials.get()`. */
|
|
53
|
+
optionsJson: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
1
56
|
interface HttpAdapterRequest {
|
|
2
57
|
url: string;
|
|
3
58
|
method: string;
|
|
@@ -55,6 +110,30 @@ declare class LoggingHttpAdapter implements HttpAdapter {
|
|
|
55
110
|
private log;
|
|
56
111
|
}
|
|
57
112
|
|
|
113
|
+
/** Customer-side operations on an approval (`/auth/authorizations`). */
|
|
114
|
+
interface SubjectApprovals {
|
|
115
|
+
/** GET /auth/authorizations/{id} — the pending payload, to show before asking for the code. */
|
|
116
|
+
get(id: string): Promise<Approval>;
|
|
117
|
+
/** POST /auth/authorizations/{id}/webauthn/options — passkey options for approving it. */
|
|
118
|
+
webauthnOptions(id: string): Promise<ApprovalWebAuthnOptions>;
|
|
119
|
+
/**
|
|
120
|
+
* POST /auth/authorizations/{id}/confirm — approves it.
|
|
121
|
+
*
|
|
122
|
+
* Pass the authenticator code or passkey assertion to verify the second
|
|
123
|
+
* factor inline (recommended). Without `input`, the session itself must
|
|
124
|
+
* have used a passkey or authenticator code within the last 5 minutes,
|
|
125
|
+
* otherwise the API answers `step_up_required`.
|
|
126
|
+
*/
|
|
127
|
+
confirm(id: string, input?: ConfirmApprovalInput): Promise<Approval>;
|
|
128
|
+
/** POST /auth/authorizations/{id}/reject — the customer declines it. */
|
|
129
|
+
reject(id: string): Promise<Approval>;
|
|
130
|
+
}
|
|
131
|
+
/** The `security` namespace an end-user client exposes. */
|
|
132
|
+
interface SubjectSecurity {
|
|
133
|
+
/** Approve or reject what your backend asked the customer to confirm. */
|
|
134
|
+
readonly approvals: SubjectApprovals;
|
|
135
|
+
}
|
|
136
|
+
|
|
58
137
|
interface PaginationOptions {
|
|
59
138
|
skip?: number;
|
|
60
139
|
take?: number;
|
|
@@ -518,6 +597,13 @@ declare class AuthyonClient {
|
|
|
518
597
|
assertionStart: (challengeToken: string) => Promise<WebAuthnCeremonyStart>;
|
|
519
598
|
};
|
|
520
599
|
};
|
|
600
|
+
/**
|
|
601
|
+
* `security.approvals`: approve or reject what your backend asked the
|
|
602
|
+
* customer to confirm (`@authyon/server` → `security.approvals.create`).
|
|
603
|
+
* Show the payload with `get()`, then `confirm()` with the customer's
|
|
604
|
+
* authenticator code or passkey, or `reject()`.
|
|
605
|
+
*/
|
|
606
|
+
readonly security: SubjectSecurity;
|
|
521
607
|
/**
|
|
522
608
|
* POST /auth/introspect — lightweight token introspection (RFC 7662).
|
|
523
609
|
*
|
|
@@ -642,4 +728,4 @@ declare function hasPermissionGroup(source: AuthyonPermissionSource | readonly s
|
|
|
642
728
|
/** Converts Authyon's `subject:action` permission strings to authorization rules. */
|
|
643
729
|
declare function createAuthyonRules(source?: AuthyonPermissionSource, options?: AuthyonAbilityOptions): AbilityRule[];
|
|
644
730
|
|
|
645
|
-
export {
|
|
731
|
+
export { type TwoFactorMethod as $, AuthyonClient as A, type InviteMemberInput as B, type ConfirmApprovalInput as C, type LoginInput as D, type LoginResult as E, FetchHttpAdapter as F, type OrganizationMember as G, type HttpAdapter as H, type IntrospectResult as I, type PaginationOptions as J, type PermissionGroup as K, LoggingHttpAdapter as L, type Role as M, type SessionControllerOptions as N, type Organization as O, type Paged as P, type SessionInfo as Q, type RegisterInput as R, type Session as S, type TokenStorage as T, type SessionSnapshot as U, type SessionSnapshotListener as V, type SessionStatus as W, type SsoProvider as X, type SubjectApprovals as Y, type SubjectSecurity as Z, type TwoFactorChallenge as _, type HttpLoggerOptions as a, type TwoFactorStatus as a0, type User as a1, type ValidateResult as a2, type VerifyTwoFactorInput as a3, type WebAuthnAssertion as a4, type WebAuthnCeremonyStart as a5, type WebAuthnCredential as a6, createAuthyonAbility as a7, createAuthyonRules as a8, createClient as a9, hasPermission as aa, hasPermissionGroup as ab, type AbilityConditions as b, type AbilityEvent as c, type AbilityListener as d, type AbilityRule as e, type AbilitySubject as f, type Activity as g, type Approval as h, type ApprovalAssurance as i, type ApprovalPayload as j, type ApprovalStatus as k, type ApprovalWebAuthnOptions as l, type AuthEvent as m, type AuthState as n, type AuthStateListener as o, type AuthenticatorSetup as p, AuthyonAbility as q, AuthyonAbilityBuilder as r, type AuthyonAbilityOptions as s, type AuthyonClientOptions as t, type AuthyonPermissionSource as u, AuthyonSessionController as v, type CreateOrganizationInput as w, type HttpAdapterRequest as x, type HttpLogEvent as y, type HttpLogger as z };
|
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,23 @@ __export(index_exports, {
|
|
|
40
40
|
});
|
|
41
41
|
module.exports = __toCommonJS(index_exports);
|
|
42
42
|
|
|
43
|
+
// ../../internal/core/security/approvals.ts
|
|
44
|
+
function path(id, suffix = "") {
|
|
45
|
+
if (typeof id !== "string" || !id.trim())
|
|
46
|
+
throw new TypeError("Authyon: an approval id is required.");
|
|
47
|
+
return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
|
|
48
|
+
}
|
|
49
|
+
function subjectSecurity(request) {
|
|
50
|
+
return {
|
|
51
|
+
approvals: {
|
|
52
|
+
get: (id) => request(path(id)),
|
|
53
|
+
webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
|
|
54
|
+
confirm: (id, input) => request(path(id, "/confirm"), { method: "POST", body: input }),
|
|
55
|
+
reject: (id) => request(path(id, "/reject"), { method: "POST" })
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
43
60
|
// ../../internal/core/errors/authyonError.ts
|
|
44
61
|
var ErrorCodes = {
|
|
45
62
|
Unknown: "unknown",
|
|
@@ -52,16 +69,44 @@ var ErrorCodes = {
|
|
|
52
69
|
EmailTaken: "user.email_taken",
|
|
53
70
|
PasswordWeak: "user.password_weak",
|
|
54
71
|
PasswordPwned: "user.password_pwned",
|
|
55
|
-
RateLimited: "rate_limited"
|
|
72
|
+
RateLimited: "rate_limited",
|
|
73
|
+
StepUpRequired: "step_up_required",
|
|
74
|
+
InvalidSecondFactorCode: "invalid_code",
|
|
75
|
+
VerificationAttemptsExhausted: "verification_attempts_exhausted",
|
|
76
|
+
MethodNotEnrolled: "method_not_enrolled",
|
|
77
|
+
InvalidApprovalState: "invalid_authorization_state",
|
|
78
|
+
PayloadMismatch: "payload_mismatch",
|
|
79
|
+
ApprovalNotConsumable: "authorization_not_consumable",
|
|
80
|
+
IdempotencyConflict: "idempotency_conflict",
|
|
81
|
+
UserDisabled: "user_disabled",
|
|
82
|
+
UserNotFound: "user_not_found",
|
|
83
|
+
TemporarilyUnavailable: "temporarily_unavailable",
|
|
84
|
+
InsufficientScope: "insufficient_scope",
|
|
85
|
+
ApprovalNotFound: "authorization_not_found",
|
|
86
|
+
SessionRevoked: "session_revoked",
|
|
87
|
+
TwoFactorTooManyFailures: "user.2fa.too_many_failures"
|
|
56
88
|
};
|
|
89
|
+
var STANDARD_ERROR_FIELDS = /* @__PURE__ */ new Set([
|
|
90
|
+
"type",
|
|
91
|
+
"status",
|
|
92
|
+
"title",
|
|
93
|
+
"detail",
|
|
94
|
+
"code",
|
|
95
|
+
"error",
|
|
96
|
+
"error_description"
|
|
97
|
+
]);
|
|
57
98
|
var AuthyonError = class extends Error {
|
|
58
99
|
constructor(status, body, options = {}) {
|
|
59
|
-
|
|
100
|
+
const detail = body.detail ?? body.error_description;
|
|
101
|
+
super(detail ?? body.title ?? `Authyon request failed with status ${status}`);
|
|
60
102
|
this.name = "AuthyonError";
|
|
61
103
|
this.status = status;
|
|
62
|
-
this.code = body.code ?? "unknown";
|
|
104
|
+
this.code = body.code ?? body.error ?? "unknown";
|
|
63
105
|
this.title = body.title ?? "Error";
|
|
64
|
-
this.detail =
|
|
106
|
+
this.detail = detail;
|
|
107
|
+
this.extensions = Object.fromEntries(
|
|
108
|
+
Object.entries(body).filter(([key]) => !STANDARD_ERROR_FIELDS.has(key))
|
|
109
|
+
);
|
|
65
110
|
this.requestId = options.requestId;
|
|
66
111
|
this.retryAfter = options.retryAfter;
|
|
67
112
|
this.cause = options.cause;
|
|
@@ -111,6 +156,7 @@ var AuthyonError = class extends Error {
|
|
|
111
156
|
};
|
|
112
157
|
function classifyError(status, code) {
|
|
113
158
|
if (code === ErrorCodes.NetworkError) return "network";
|
|
159
|
+
if (code === ErrorCodes.StepUpRequired) return "authentication";
|
|
114
160
|
if (code === ErrorCodes.Timeout || status === 408) return "timeout";
|
|
115
161
|
if (code === ErrorCodes.RateLimited || status === 429) return "rate_limit";
|
|
116
162
|
if (code === ErrorCodes.EmailTaken || status === 409) return "conflict";
|
|
@@ -204,14 +250,14 @@ var DEFAULT_BASE_URL = "https://api.authyon.com";
|
|
|
204
250
|
var DEFAULT_EXPIRY_SKEW_MS = 3e4;
|
|
205
251
|
|
|
206
252
|
// ../../internal/core/http/query.ts
|
|
207
|
-
function appendQuery(
|
|
208
|
-
if (!params) return
|
|
253
|
+
function appendQuery(path2, params) {
|
|
254
|
+
if (!params) return path2;
|
|
209
255
|
const query = new URLSearchParams();
|
|
210
256
|
for (const [key, value2] of Object.entries(params)) {
|
|
211
257
|
if (value2 !== void 0) query.set(key, String(value2));
|
|
212
258
|
}
|
|
213
259
|
const value = query.toString();
|
|
214
|
-
return value ? `${
|
|
260
|
+
return value ? `${path2}${path2.includes("?") ? "&" : "?"}${value}` : path2;
|
|
215
261
|
}
|
|
216
262
|
|
|
217
263
|
// ../../internal/core/http/httpAdapter.ts
|
|
@@ -280,7 +326,6 @@ function sanitizeUrl(value) {
|
|
|
280
326
|
url.username = "";
|
|
281
327
|
url.password = "";
|
|
282
328
|
url.hash = "";
|
|
283
|
-
url.pathname = url.pathname.replace(/(\/platform\/workspace-invites\/)[^/]+/u, "$1REDACTED");
|
|
284
329
|
const queryKeys = /* @__PURE__ */ new Set();
|
|
285
330
|
url.searchParams.forEach((_value, key) => queryKeys.add(key));
|
|
286
331
|
url.search = queryKeys.size > 0 ? [...queryKeys].map((key) => `${encodeURIComponent(key)}=REDACTED`).join("&") : "";
|
|
@@ -310,12 +355,12 @@ function createSharedTransport(options) {
|
|
|
310
355
|
const httpAdapter = options.httpLogger ? new LoggingHttpAdapter(baseAdapter, options.httpLogger) : baseAdapter;
|
|
311
356
|
return {
|
|
312
357
|
baseUrl,
|
|
313
|
-
async request(
|
|
358
|
+
async request(path2, init) {
|
|
314
359
|
const controller = new AbortController();
|
|
315
360
|
const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
|
|
316
361
|
try {
|
|
317
362
|
return await httpAdapter.request({
|
|
318
|
-
url: `${baseUrl}${
|
|
363
|
+
url: `${baseUrl}${path2}`,
|
|
319
364
|
method: init.method ?? "GET",
|
|
320
365
|
headers: normalizeHeaders(init.headers),
|
|
321
366
|
body: init.body,
|
|
@@ -373,11 +418,11 @@ var JsonHttpClient = class {
|
|
|
373
418
|
constructor(transport) {
|
|
374
419
|
this.transport = transport;
|
|
375
420
|
}
|
|
376
|
-
async send(
|
|
421
|
+
async send(path2, options = {}) {
|
|
377
422
|
const headers = { ...options.headers };
|
|
378
423
|
if (options.body !== void 0) headers["Content-Type"] = "application/json";
|
|
379
424
|
try {
|
|
380
|
-
return await this.transport.request(appendQuery(
|
|
425
|
+
return await this.transport.request(appendQuery(path2, options.query), {
|
|
381
426
|
method: options.method ?? "GET",
|
|
382
427
|
headers,
|
|
383
428
|
body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
|
|
@@ -391,7 +436,9 @@ var JsonHttpClient = class {
|
|
|
391
436
|
if (!response.ok) {
|
|
392
437
|
let body = {};
|
|
393
438
|
try {
|
|
394
|
-
|
|
439
|
+
const parsed = await response.json();
|
|
440
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
441
|
+
body = parsed;
|
|
395
442
|
} catch {
|
|
396
443
|
}
|
|
397
444
|
throw new AuthyonError(response.status, body, responseMetadata(response));
|
|
@@ -399,8 +446,8 @@ var JsonHttpClient = class {
|
|
|
399
446
|
if (response.status === 204) return void 0;
|
|
400
447
|
return await response.json();
|
|
401
448
|
}
|
|
402
|
-
async request(
|
|
403
|
-
return this.parse(await this.send(
|
|
449
|
+
async request(path2, options = {}) {
|
|
450
|
+
return this.parse(await this.send(path2, options));
|
|
404
451
|
}
|
|
405
452
|
};
|
|
406
453
|
|
|
@@ -638,6 +685,16 @@ var AuthyonClient = class {
|
|
|
638
685
|
})
|
|
639
686
|
}
|
|
640
687
|
};
|
|
688
|
+
// ── Security (customer side) ─────────────────────────────────────────────
|
|
689
|
+
/**
|
|
690
|
+
* `security.approvals`: approve or reject what your backend asked the
|
|
691
|
+
* customer to confirm (`@authyon/server` → `security.approvals.create`).
|
|
692
|
+
* Show the payload with `get()`, then `confirm()` with the customer's
|
|
693
|
+
* authenticator code or passkey, or `reject()`.
|
|
694
|
+
*/
|
|
695
|
+
this.security = subjectSecurity(
|
|
696
|
+
(path2, options) => this.request(path2, { ...options, bearer: true })
|
|
697
|
+
);
|
|
641
698
|
if (!options.envKey)
|
|
642
699
|
throw new Error("Authyon: `envKey` is required (pk_live_... / pk_test_...)");
|
|
643
700
|
this.envKey = options.envKey;
|
|
@@ -751,7 +808,7 @@ var AuthyonClient = class {
|
|
|
751
808
|
}
|
|
752
809
|
}
|
|
753
810
|
// ── HTTP core ────────────────────────────────────────────────────────────
|
|
754
|
-
async request(
|
|
811
|
+
async request(path2, options = {}, isRetry = false) {
|
|
755
812
|
const headers = {
|
|
756
813
|
"X-Authyon-Environment": this.envKey,
|
|
757
814
|
...clientIpHeaders({ clientIp: this.clientIp }),
|
|
@@ -766,7 +823,7 @@ var AuthyonClient = class {
|
|
|
766
823
|
});
|
|
767
824
|
headers.Authorization = `Bearer ${token}`;
|
|
768
825
|
}
|
|
769
|
-
const response = await this.http.send(
|
|
826
|
+
const response = await this.http.send(path2, { ...options, headers });
|
|
770
827
|
if (response.status === 401 && options.bearer && this.autoRefresh && !isRetry && this.getSession()) {
|
|
771
828
|
try {
|
|
772
829
|
await this.refresh();
|
|
@@ -774,7 +831,7 @@ var AuthyonClient = class {
|
|
|
774
831
|
this.clearSession();
|
|
775
832
|
return this.http.parse(response);
|
|
776
833
|
}
|
|
777
|
-
return this.request(
|
|
834
|
+
return this.request(path2, options, true);
|
|
778
835
|
}
|
|
779
836
|
return this.http.parse(response);
|
|
780
837
|
}
|
|
@@ -1193,18 +1250,18 @@ function matchesField(pattern, field) {
|
|
|
1193
1250
|
return pattern.endsWith(".*") && field.startsWith(pattern.slice(0, -1));
|
|
1194
1251
|
}
|
|
1195
1252
|
function matchesConditions(subject, conditions) {
|
|
1196
|
-
return Object.entries(conditions).every(([
|
|
1197
|
-
if (
|
|
1253
|
+
return Object.entries(conditions).every(([path2, expected]) => {
|
|
1254
|
+
if (path2 === "$and" && Array.isArray(expected)) {
|
|
1198
1255
|
return expected.every(
|
|
1199
1256
|
(condition) => matchesConditions(subject, condition)
|
|
1200
1257
|
);
|
|
1201
1258
|
}
|
|
1202
|
-
if (
|
|
1259
|
+
if (path2 === "$or" && Array.isArray(expected)) {
|
|
1203
1260
|
return expected.some(
|
|
1204
1261
|
(condition) => matchesConditions(subject, condition)
|
|
1205
1262
|
);
|
|
1206
1263
|
}
|
|
1207
|
-
return matchesValue(readPath(subject,
|
|
1264
|
+
return matchesValue(readPath(subject, path2), expected);
|
|
1208
1265
|
});
|
|
1209
1266
|
}
|
|
1210
1267
|
function matchesValue(actual, expected) {
|
|
@@ -1236,8 +1293,8 @@ function matchesValue(actual, expected) {
|
|
|
1236
1293
|
}
|
|
1237
1294
|
});
|
|
1238
1295
|
}
|
|
1239
|
-
function readPath(value,
|
|
1240
|
-
return
|
|
1296
|
+
function readPath(value, path2) {
|
|
1297
|
+
return path2.split(".").reduce((current, part) => isRecord(current) ? current[part] : void 0, value);
|
|
1241
1298
|
}
|
|
1242
1299
|
function defaultSubjectType(subject) {
|
|
1243
1300
|
const explicit = subject.__type ?? subject.type ?? subject.kind;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
import { T as TokenStorage, H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonClient } from './ability-
|
|
2
|
-
export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRule, f as AbilitySubject, g as Activity, h as
|
|
3
|
-
|
|
4
|
-
/** Builds an Authyon browser client through explicit, progressive configuration. */
|
|
5
|
-
declare class AuthyonClientBuilder {
|
|
6
|
-
private readonly options;
|
|
7
|
-
constructor(envKey: string);
|
|
8
|
-
withBaseUrl(baseUrl: string, allowInsecureHttp?: boolean): this;
|
|
9
|
-
withStorage(storage: TokenStorage): this;
|
|
10
|
-
withAutomaticRefresh(enabled?: boolean): this;
|
|
11
|
-
withClientIp(clientIp: string): this;
|
|
12
|
-
withTimeout(timeoutMs: number): this;
|
|
13
|
-
withHttpAdapter(httpAdapter: HttpAdapter): this;
|
|
14
|
-
withHttpLogger(httpLogger: HttpLoggerOptions): this;
|
|
15
|
-
build(): AuthyonClient;
|
|
16
|
-
}
|
|
1
|
+
import { T as TokenStorage, H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonClient } from './ability-5_xXXbDF.cjs';
|
|
2
|
+
export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRule, f as AbilitySubject, g as Activity, h as Approval, i as ApprovalAssurance, j as ApprovalPayload, k as ApprovalStatus, l as ApprovalWebAuthnOptions, m as AuthEvent, n as AuthState, o as AuthStateListener, p as AuthenticatorSetup, q as AuthyonAbility, r as AuthyonAbilityBuilder, s as AuthyonAbilityOptions, t as AuthyonClientOptions, u as AuthyonPermissionSource, v as AuthyonSessionController, C as ConfirmApprovalInput, w as CreateOrganizationInput, F as FetchHttpAdapter, x as HttpAdapterRequest, y as HttpLogEvent, z as HttpLogger, I as IntrospectResult, B as InviteMemberInput, L as LoggingHttpAdapter, D as LoginInput, E as LoginResult, O as Organization, G as OrganizationMember, P as Paged, J as PaginationOptions, K as PermissionGroup, R as RegisterInput, M as Role, S as Session, N as SessionControllerOptions, Q as SessionInfo, U as SessionSnapshot, V as SessionSnapshotListener, W as SessionStatus, X as SsoProvider, Y as SubjectApprovals, Z as SubjectSecurity, _ as TwoFactorChallenge, $ as TwoFactorMethod, a0 as TwoFactorStatus, a1 as User, a2 as ValidateResult, a3 as VerifyTwoFactorInput, a4 as WebAuthnAssertion, a5 as WebAuthnCeremonyStart, a6 as WebAuthnCredential, a7 as createAuthyonAbility, a8 as createAuthyonRules, a9 as createClient, aa as hasPermission, ab as hasPermissionGroup } from './ability-5_xXXbDF.cjs';
|
|
17
3
|
|
|
18
4
|
declare const ErrorCodes: {
|
|
19
5
|
readonly Unknown: "unknown";
|
|
@@ -27,6 +13,21 @@ declare const ErrorCodes: {
|
|
|
27
13
|
readonly PasswordWeak: "user.password_weak";
|
|
28
14
|
readonly PasswordPwned: "user.password_pwned";
|
|
29
15
|
readonly RateLimited: "rate_limited";
|
|
16
|
+
readonly StepUpRequired: "step_up_required";
|
|
17
|
+
readonly InvalidSecondFactorCode: "invalid_code";
|
|
18
|
+
readonly VerificationAttemptsExhausted: "verification_attempts_exhausted";
|
|
19
|
+
readonly MethodNotEnrolled: "method_not_enrolled";
|
|
20
|
+
readonly InvalidApprovalState: "invalid_authorization_state";
|
|
21
|
+
readonly PayloadMismatch: "payload_mismatch";
|
|
22
|
+
readonly ApprovalNotConsumable: "authorization_not_consumable";
|
|
23
|
+
readonly IdempotencyConflict: "idempotency_conflict";
|
|
24
|
+
readonly UserDisabled: "user_disabled";
|
|
25
|
+
readonly UserNotFound: "user_not_found";
|
|
26
|
+
readonly TemporarilyUnavailable: "temporarily_unavailable";
|
|
27
|
+
readonly InsufficientScope: "insufficient_scope";
|
|
28
|
+
readonly ApprovalNotFound: "authorization_not_found";
|
|
29
|
+
readonly SessionRevoked: "session_revoked";
|
|
30
|
+
readonly TwoFactorTooManyFailures: "user.2fa.too_many_failures";
|
|
30
31
|
};
|
|
31
32
|
type KnownErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|
|
32
33
|
type AuthyonErrorCategory = "network" | "timeout" | "authentication" | "authorization" | "validation" | "not_found" | "conflict" | "rate_limit" | "server" | "unknown";
|
|
@@ -38,6 +39,14 @@ interface AuthyonErrorInterpretation {
|
|
|
38
39
|
retryAfter?: number;
|
|
39
40
|
requestId?: string;
|
|
40
41
|
}
|
|
42
|
+
/** Error body as sent by the API: RFC 7807, or OAuth-style `error`/`error_description`. */
|
|
43
|
+
type AuthyonErrorBody = Partial<{
|
|
44
|
+
title: string;
|
|
45
|
+
detail: string;
|
|
46
|
+
code: string;
|
|
47
|
+
error: string;
|
|
48
|
+
error_description: string;
|
|
49
|
+
}> & Record<string, unknown>;
|
|
41
50
|
/** Shared RFC 7807 error implementation used by both public SDKs. */
|
|
42
51
|
declare class AuthyonError extends Error {
|
|
43
52
|
readonly status: number;
|
|
@@ -47,11 +56,13 @@ declare class AuthyonError extends Error {
|
|
|
47
56
|
readonly requestId?: string;
|
|
48
57
|
readonly retryAfter?: number;
|
|
49
58
|
readonly cause?: unknown;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Extra fields from the error body beyond code/title/detail — e.g.
|
|
61
|
+
* `attemptsRemaining` on `invalid_code` or `requiredMethods` on
|
|
62
|
+
* `step_up_required`. Not included in {@link toJSON}.
|
|
63
|
+
*/
|
|
64
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
65
|
+
constructor(status: number, body: AuthyonErrorBody, options?: {
|
|
55
66
|
requestId?: string;
|
|
56
67
|
retryAfter?: number;
|
|
57
68
|
cause?: unknown;
|
|
@@ -67,10 +78,24 @@ declare class AuthyonError extends Error {
|
|
|
67
78
|
toJSON(): Record<string, unknown>;
|
|
68
79
|
}
|
|
69
80
|
|
|
81
|
+
/** Builds an Authyon browser client through explicit, progressive configuration. */
|
|
82
|
+
declare class AuthyonClientBuilder {
|
|
83
|
+
private readonly options;
|
|
84
|
+
constructor(envKey: string);
|
|
85
|
+
withBaseUrl(baseUrl: string, allowInsecureHttp?: boolean): this;
|
|
86
|
+
withStorage(storage: TokenStorage): this;
|
|
87
|
+
withAutomaticRefresh(enabled?: boolean): this;
|
|
88
|
+
withClientIp(clientIp: string): this;
|
|
89
|
+
withTimeout(timeoutMs: number): this;
|
|
90
|
+
withHttpAdapter(httpAdapter: HttpAdapter): this;
|
|
91
|
+
withHttpLogger(httpLogger: HttpLoggerOptions): this;
|
|
92
|
+
build(): AuthyonClient;
|
|
93
|
+
}
|
|
94
|
+
|
|
70
95
|
/** Keeps the session in memory only (lost on page reload). */
|
|
71
96
|
declare function createMemoryStorage(): TokenStorage;
|
|
72
97
|
/** Persists the session in `localStorage` under a namespaced key. */
|
|
73
98
|
declare function createLocalStorage(key?: string): TokenStorage;
|
|
74
99
|
declare function createDefaultStorage(): TokenStorage;
|
|
75
100
|
|
|
76
|
-
export { AuthyonClient, AuthyonClientBuilder, AuthyonError, type AuthyonErrorAction, type AuthyonErrorCategory, type AuthyonErrorInterpretation, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode, TokenStorage, createDefaultStorage, createLocalStorage, createMemoryStorage };
|
|
101
|
+
export { AuthyonClient, AuthyonClientBuilder, AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode, TokenStorage, createDefaultStorage, createLocalStorage, createMemoryStorage };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
import { T as TokenStorage, H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonClient } from './ability-
|
|
2
|
-
export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRule, f as AbilitySubject, g as Activity, h as
|
|
3
|
-
|
|
4
|
-
/** Builds an Authyon browser client through explicit, progressive configuration. */
|
|
5
|
-
declare class AuthyonClientBuilder {
|
|
6
|
-
private readonly options;
|
|
7
|
-
constructor(envKey: string);
|
|
8
|
-
withBaseUrl(baseUrl: string, allowInsecureHttp?: boolean): this;
|
|
9
|
-
withStorage(storage: TokenStorage): this;
|
|
10
|
-
withAutomaticRefresh(enabled?: boolean): this;
|
|
11
|
-
withClientIp(clientIp: string): this;
|
|
12
|
-
withTimeout(timeoutMs: number): this;
|
|
13
|
-
withHttpAdapter(httpAdapter: HttpAdapter): this;
|
|
14
|
-
withHttpLogger(httpLogger: HttpLoggerOptions): this;
|
|
15
|
-
build(): AuthyonClient;
|
|
16
|
-
}
|
|
1
|
+
import { T as TokenStorage, H as HttpAdapter, a as HttpLoggerOptions, A as AuthyonClient } from './ability-5_xXXbDF.js';
|
|
2
|
+
export { b as AbilityConditions, c as AbilityEvent, d as AbilityListener, e as AbilityRule, f as AbilitySubject, g as Activity, h as Approval, i as ApprovalAssurance, j as ApprovalPayload, k as ApprovalStatus, l as ApprovalWebAuthnOptions, m as AuthEvent, n as AuthState, o as AuthStateListener, p as AuthenticatorSetup, q as AuthyonAbility, r as AuthyonAbilityBuilder, s as AuthyonAbilityOptions, t as AuthyonClientOptions, u as AuthyonPermissionSource, v as AuthyonSessionController, C as ConfirmApprovalInput, w as CreateOrganizationInput, F as FetchHttpAdapter, x as HttpAdapterRequest, y as HttpLogEvent, z as HttpLogger, I as IntrospectResult, B as InviteMemberInput, L as LoggingHttpAdapter, D as LoginInput, E as LoginResult, O as Organization, G as OrganizationMember, P as Paged, J as PaginationOptions, K as PermissionGroup, R as RegisterInput, M as Role, S as Session, N as SessionControllerOptions, Q as SessionInfo, U as SessionSnapshot, V as SessionSnapshotListener, W as SessionStatus, X as SsoProvider, Y as SubjectApprovals, Z as SubjectSecurity, _ as TwoFactorChallenge, $ as TwoFactorMethod, a0 as TwoFactorStatus, a1 as User, a2 as ValidateResult, a3 as VerifyTwoFactorInput, a4 as WebAuthnAssertion, a5 as WebAuthnCeremonyStart, a6 as WebAuthnCredential, a7 as createAuthyonAbility, a8 as createAuthyonRules, a9 as createClient, aa as hasPermission, ab as hasPermissionGroup } from './ability-5_xXXbDF.js';
|
|
17
3
|
|
|
18
4
|
declare const ErrorCodes: {
|
|
19
5
|
readonly Unknown: "unknown";
|
|
@@ -27,6 +13,21 @@ declare const ErrorCodes: {
|
|
|
27
13
|
readonly PasswordWeak: "user.password_weak";
|
|
28
14
|
readonly PasswordPwned: "user.password_pwned";
|
|
29
15
|
readonly RateLimited: "rate_limited";
|
|
16
|
+
readonly StepUpRequired: "step_up_required";
|
|
17
|
+
readonly InvalidSecondFactorCode: "invalid_code";
|
|
18
|
+
readonly VerificationAttemptsExhausted: "verification_attempts_exhausted";
|
|
19
|
+
readonly MethodNotEnrolled: "method_not_enrolled";
|
|
20
|
+
readonly InvalidApprovalState: "invalid_authorization_state";
|
|
21
|
+
readonly PayloadMismatch: "payload_mismatch";
|
|
22
|
+
readonly ApprovalNotConsumable: "authorization_not_consumable";
|
|
23
|
+
readonly IdempotencyConflict: "idempotency_conflict";
|
|
24
|
+
readonly UserDisabled: "user_disabled";
|
|
25
|
+
readonly UserNotFound: "user_not_found";
|
|
26
|
+
readonly TemporarilyUnavailable: "temporarily_unavailable";
|
|
27
|
+
readonly InsufficientScope: "insufficient_scope";
|
|
28
|
+
readonly ApprovalNotFound: "authorization_not_found";
|
|
29
|
+
readonly SessionRevoked: "session_revoked";
|
|
30
|
+
readonly TwoFactorTooManyFailures: "user.2fa.too_many_failures";
|
|
30
31
|
};
|
|
31
32
|
type KnownErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|
|
32
33
|
type AuthyonErrorCategory = "network" | "timeout" | "authentication" | "authorization" | "validation" | "not_found" | "conflict" | "rate_limit" | "server" | "unknown";
|
|
@@ -38,6 +39,14 @@ interface AuthyonErrorInterpretation {
|
|
|
38
39
|
retryAfter?: number;
|
|
39
40
|
requestId?: string;
|
|
40
41
|
}
|
|
42
|
+
/** Error body as sent by the API: RFC 7807, or OAuth-style `error`/`error_description`. */
|
|
43
|
+
type AuthyonErrorBody = Partial<{
|
|
44
|
+
title: string;
|
|
45
|
+
detail: string;
|
|
46
|
+
code: string;
|
|
47
|
+
error: string;
|
|
48
|
+
error_description: string;
|
|
49
|
+
}> & Record<string, unknown>;
|
|
41
50
|
/** Shared RFC 7807 error implementation used by both public SDKs. */
|
|
42
51
|
declare class AuthyonError extends Error {
|
|
43
52
|
readonly status: number;
|
|
@@ -47,11 +56,13 @@ declare class AuthyonError extends Error {
|
|
|
47
56
|
readonly requestId?: string;
|
|
48
57
|
readonly retryAfter?: number;
|
|
49
58
|
readonly cause?: unknown;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Extra fields from the error body beyond code/title/detail — e.g.
|
|
61
|
+
* `attemptsRemaining` on `invalid_code` or `requiredMethods` on
|
|
62
|
+
* `step_up_required`. Not included in {@link toJSON}.
|
|
63
|
+
*/
|
|
64
|
+
readonly extensions: Readonly<Record<string, unknown>>;
|
|
65
|
+
constructor(status: number, body: AuthyonErrorBody, options?: {
|
|
55
66
|
requestId?: string;
|
|
56
67
|
retryAfter?: number;
|
|
57
68
|
cause?: unknown;
|
|
@@ -67,10 +78,24 @@ declare class AuthyonError extends Error {
|
|
|
67
78
|
toJSON(): Record<string, unknown>;
|
|
68
79
|
}
|
|
69
80
|
|
|
81
|
+
/** Builds an Authyon browser client through explicit, progressive configuration. */
|
|
82
|
+
declare class AuthyonClientBuilder {
|
|
83
|
+
private readonly options;
|
|
84
|
+
constructor(envKey: string);
|
|
85
|
+
withBaseUrl(baseUrl: string, allowInsecureHttp?: boolean): this;
|
|
86
|
+
withStorage(storage: TokenStorage): this;
|
|
87
|
+
withAutomaticRefresh(enabled?: boolean): this;
|
|
88
|
+
withClientIp(clientIp: string): this;
|
|
89
|
+
withTimeout(timeoutMs: number): this;
|
|
90
|
+
withHttpAdapter(httpAdapter: HttpAdapter): this;
|
|
91
|
+
withHttpLogger(httpLogger: HttpLoggerOptions): this;
|
|
92
|
+
build(): AuthyonClient;
|
|
93
|
+
}
|
|
94
|
+
|
|
70
95
|
/** Keeps the session in memory only (lost on page reload). */
|
|
71
96
|
declare function createMemoryStorage(): TokenStorage;
|
|
72
97
|
/** Persists the session in `localStorage` under a namespaced key. */
|
|
73
98
|
declare function createLocalStorage(key?: string): TokenStorage;
|
|
74
99
|
declare function createDefaultStorage(): TokenStorage;
|
|
75
100
|
|
|
76
|
-
export { AuthyonClient, AuthyonClientBuilder, AuthyonError, type AuthyonErrorAction, type AuthyonErrorCategory, type AuthyonErrorInterpretation, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode, TokenStorage, createDefaultStorage, createLocalStorage, createMemoryStorage };
|
|
101
|
+
export { AuthyonClient, AuthyonClientBuilder, AuthyonError, type AuthyonErrorAction, type AuthyonErrorBody, type AuthyonErrorCategory, type AuthyonErrorInterpretation, ErrorCodes, HttpAdapter, HttpLoggerOptions, type KnownErrorCode, TokenStorage, createDefaultStorage, createLocalStorage, createMemoryStorage };
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,23 @@ import {
|
|
|
8
8
|
hasPermissionGroup
|
|
9
9
|
} from "./chunk-3XJY6BCI.js";
|
|
10
10
|
|
|
11
|
+
// ../../internal/core/security/approvals.ts
|
|
12
|
+
function path(id, suffix = "") {
|
|
13
|
+
if (typeof id !== "string" || !id.trim())
|
|
14
|
+
throw new TypeError("Authyon: an approval id is required.");
|
|
15
|
+
return `/auth/authorizations/${encodeURIComponent(id)}${suffix}`;
|
|
16
|
+
}
|
|
17
|
+
function subjectSecurity(request) {
|
|
18
|
+
return {
|
|
19
|
+
approvals: {
|
|
20
|
+
get: (id) => request(path(id)),
|
|
21
|
+
webauthnOptions: (id) => request(path(id, "/webauthn/options"), { method: "POST" }),
|
|
22
|
+
confirm: (id, input) => request(path(id, "/confirm"), { method: "POST", body: input }),
|
|
23
|
+
reject: (id) => request(path(id, "/reject"), { method: "POST" })
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
11
28
|
// ../../internal/core/errors/authyonError.ts
|
|
12
29
|
var ErrorCodes = {
|
|
13
30
|
Unknown: "unknown",
|
|
@@ -20,16 +37,44 @@ var ErrorCodes = {
|
|
|
20
37
|
EmailTaken: "user.email_taken",
|
|
21
38
|
PasswordWeak: "user.password_weak",
|
|
22
39
|
PasswordPwned: "user.password_pwned",
|
|
23
|
-
RateLimited: "rate_limited"
|
|
40
|
+
RateLimited: "rate_limited",
|
|
41
|
+
StepUpRequired: "step_up_required",
|
|
42
|
+
InvalidSecondFactorCode: "invalid_code",
|
|
43
|
+
VerificationAttemptsExhausted: "verification_attempts_exhausted",
|
|
44
|
+
MethodNotEnrolled: "method_not_enrolled",
|
|
45
|
+
InvalidApprovalState: "invalid_authorization_state",
|
|
46
|
+
PayloadMismatch: "payload_mismatch",
|
|
47
|
+
ApprovalNotConsumable: "authorization_not_consumable",
|
|
48
|
+
IdempotencyConflict: "idempotency_conflict",
|
|
49
|
+
UserDisabled: "user_disabled",
|
|
50
|
+
UserNotFound: "user_not_found",
|
|
51
|
+
TemporarilyUnavailable: "temporarily_unavailable",
|
|
52
|
+
InsufficientScope: "insufficient_scope",
|
|
53
|
+
ApprovalNotFound: "authorization_not_found",
|
|
54
|
+
SessionRevoked: "session_revoked",
|
|
55
|
+
TwoFactorTooManyFailures: "user.2fa.too_many_failures"
|
|
24
56
|
};
|
|
57
|
+
var STANDARD_ERROR_FIELDS = /* @__PURE__ */ new Set([
|
|
58
|
+
"type",
|
|
59
|
+
"status",
|
|
60
|
+
"title",
|
|
61
|
+
"detail",
|
|
62
|
+
"code",
|
|
63
|
+
"error",
|
|
64
|
+
"error_description"
|
|
65
|
+
]);
|
|
25
66
|
var AuthyonError = class extends Error {
|
|
26
67
|
constructor(status, body, options = {}) {
|
|
27
|
-
|
|
68
|
+
const detail = body.detail ?? body.error_description;
|
|
69
|
+
super(detail ?? body.title ?? `Authyon request failed with status ${status}`);
|
|
28
70
|
this.name = "AuthyonError";
|
|
29
71
|
this.status = status;
|
|
30
|
-
this.code = body.code ?? "unknown";
|
|
72
|
+
this.code = body.code ?? body.error ?? "unknown";
|
|
31
73
|
this.title = body.title ?? "Error";
|
|
32
|
-
this.detail =
|
|
74
|
+
this.detail = detail;
|
|
75
|
+
this.extensions = Object.fromEntries(
|
|
76
|
+
Object.entries(body).filter(([key]) => !STANDARD_ERROR_FIELDS.has(key))
|
|
77
|
+
);
|
|
33
78
|
this.requestId = options.requestId;
|
|
34
79
|
this.retryAfter = options.retryAfter;
|
|
35
80
|
this.cause = options.cause;
|
|
@@ -79,6 +124,7 @@ var AuthyonError = class extends Error {
|
|
|
79
124
|
};
|
|
80
125
|
function classifyError(status, code) {
|
|
81
126
|
if (code === ErrorCodes.NetworkError) return "network";
|
|
127
|
+
if (code === ErrorCodes.StepUpRequired) return "authentication";
|
|
82
128
|
if (code === ErrorCodes.Timeout || status === 408) return "timeout";
|
|
83
129
|
if (code === ErrorCodes.RateLimited || status === 429) return "rate_limit";
|
|
84
130
|
if (code === ErrorCodes.EmailTaken || status === 409) return "conflict";
|
|
@@ -172,14 +218,14 @@ var DEFAULT_BASE_URL = "https://api.authyon.com";
|
|
|
172
218
|
var DEFAULT_EXPIRY_SKEW_MS = 3e4;
|
|
173
219
|
|
|
174
220
|
// ../../internal/core/http/query.ts
|
|
175
|
-
function appendQuery(
|
|
176
|
-
if (!params) return
|
|
221
|
+
function appendQuery(path2, params) {
|
|
222
|
+
if (!params) return path2;
|
|
177
223
|
const query = new URLSearchParams();
|
|
178
224
|
for (const [key, value2] of Object.entries(params)) {
|
|
179
225
|
if (value2 !== void 0) query.set(key, String(value2));
|
|
180
226
|
}
|
|
181
227
|
const value = query.toString();
|
|
182
|
-
return value ? `${
|
|
228
|
+
return value ? `${path2}${path2.includes("?") ? "&" : "?"}${value}` : path2;
|
|
183
229
|
}
|
|
184
230
|
|
|
185
231
|
// ../../internal/core/http/httpAdapter.ts
|
|
@@ -248,7 +294,6 @@ function sanitizeUrl(value) {
|
|
|
248
294
|
url.username = "";
|
|
249
295
|
url.password = "";
|
|
250
296
|
url.hash = "";
|
|
251
|
-
url.pathname = url.pathname.replace(/(\/platform\/workspace-invites\/)[^/]+/u, "$1REDACTED");
|
|
252
297
|
const queryKeys = /* @__PURE__ */ new Set();
|
|
253
298
|
url.searchParams.forEach((_value, key) => queryKeys.add(key));
|
|
254
299
|
url.search = queryKeys.size > 0 ? [...queryKeys].map((key) => `${encodeURIComponent(key)}=REDACTED`).join("&") : "";
|
|
@@ -278,12 +323,12 @@ function createSharedTransport(options) {
|
|
|
278
323
|
const httpAdapter = options.httpLogger ? new LoggingHttpAdapter(baseAdapter, options.httpLogger) : baseAdapter;
|
|
279
324
|
return {
|
|
280
325
|
baseUrl,
|
|
281
|
-
async request(
|
|
326
|
+
async request(path2, init) {
|
|
282
327
|
const controller = new AbortController();
|
|
283
328
|
const timeout = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
|
|
284
329
|
try {
|
|
285
330
|
return await httpAdapter.request({
|
|
286
|
-
url: `${baseUrl}${
|
|
331
|
+
url: `${baseUrl}${path2}`,
|
|
287
332
|
method: init.method ?? "GET",
|
|
288
333
|
headers: normalizeHeaders(init.headers),
|
|
289
334
|
body: init.body,
|
|
@@ -341,11 +386,11 @@ var JsonHttpClient = class {
|
|
|
341
386
|
constructor(transport) {
|
|
342
387
|
this.transport = transport;
|
|
343
388
|
}
|
|
344
|
-
async send(
|
|
389
|
+
async send(path2, options = {}) {
|
|
345
390
|
const headers = { ...options.headers };
|
|
346
391
|
if (options.body !== void 0) headers["Content-Type"] = "application/json";
|
|
347
392
|
try {
|
|
348
|
-
return await this.transport.request(appendQuery(
|
|
393
|
+
return await this.transport.request(appendQuery(path2, options.query), {
|
|
349
394
|
method: options.method ?? "GET",
|
|
350
395
|
headers,
|
|
351
396
|
body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
|
|
@@ -359,7 +404,9 @@ var JsonHttpClient = class {
|
|
|
359
404
|
if (!response.ok) {
|
|
360
405
|
let body = {};
|
|
361
406
|
try {
|
|
362
|
-
|
|
407
|
+
const parsed = await response.json();
|
|
408
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
409
|
+
body = parsed;
|
|
363
410
|
} catch {
|
|
364
411
|
}
|
|
365
412
|
throw new AuthyonError(response.status, body, responseMetadata(response));
|
|
@@ -367,8 +414,8 @@ var JsonHttpClient = class {
|
|
|
367
414
|
if (response.status === 204) return void 0;
|
|
368
415
|
return await response.json();
|
|
369
416
|
}
|
|
370
|
-
async request(
|
|
371
|
-
return this.parse(await this.send(
|
|
417
|
+
async request(path2, options = {}) {
|
|
418
|
+
return this.parse(await this.send(path2, options));
|
|
372
419
|
}
|
|
373
420
|
};
|
|
374
421
|
|
|
@@ -606,6 +653,16 @@ var AuthyonClient = class {
|
|
|
606
653
|
})
|
|
607
654
|
}
|
|
608
655
|
};
|
|
656
|
+
// ── Security (customer side) ─────────────────────────────────────────────
|
|
657
|
+
/**
|
|
658
|
+
* `security.approvals`: approve or reject what your backend asked the
|
|
659
|
+
* customer to confirm (`@authyon/server` → `security.approvals.create`).
|
|
660
|
+
* Show the payload with `get()`, then `confirm()` with the customer's
|
|
661
|
+
* authenticator code or passkey, or `reject()`.
|
|
662
|
+
*/
|
|
663
|
+
this.security = subjectSecurity(
|
|
664
|
+
(path2, options) => this.request(path2, { ...options, bearer: true })
|
|
665
|
+
);
|
|
609
666
|
if (!options.envKey)
|
|
610
667
|
throw new Error("Authyon: `envKey` is required (pk_live_... / pk_test_...)");
|
|
611
668
|
this.envKey = options.envKey;
|
|
@@ -719,7 +776,7 @@ var AuthyonClient = class {
|
|
|
719
776
|
}
|
|
720
777
|
}
|
|
721
778
|
// ── HTTP core ────────────────────────────────────────────────────────────
|
|
722
|
-
async request(
|
|
779
|
+
async request(path2, options = {}, isRetry = false) {
|
|
723
780
|
const headers = {
|
|
724
781
|
"X-Authyon-Environment": this.envKey,
|
|
725
782
|
...clientIpHeaders({ clientIp: this.clientIp }),
|
|
@@ -734,7 +791,7 @@ var AuthyonClient = class {
|
|
|
734
791
|
});
|
|
735
792
|
headers.Authorization = `Bearer ${token}`;
|
|
736
793
|
}
|
|
737
|
-
const response = await this.http.send(
|
|
794
|
+
const response = await this.http.send(path2, { ...options, headers });
|
|
738
795
|
if (response.status === 401 && options.bearer && this.autoRefresh && !isRetry && this.getSession()) {
|
|
739
796
|
try {
|
|
740
797
|
await this.refresh();
|
|
@@ -742,7 +799,7 @@ var AuthyonClient = class {
|
|
|
742
799
|
this.clearSession();
|
|
743
800
|
return this.http.parse(response);
|
|
744
801
|
}
|
|
745
|
-
return this.request(
|
|
802
|
+
return this.request(path2, options, true);
|
|
746
803
|
}
|
|
747
804
|
return this.http.parse(response);
|
|
748
805
|
}
|
package/dist/react/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
3
|
+
import { a1 as User, N as SessionControllerOptions, A as AuthyonClient, U as SessionSnapshot, S as Session, f as AbilitySubject, s as AuthyonAbilityOptions, q as AuthyonAbility } from '../ability-5_xXXbDF.cjs';
|
|
4
|
+
export { v as AuthyonSessionController, V as SessionSnapshotListener, W as SessionStatus } from '../ability-5_xXXbDF.cjs';
|
|
5
5
|
|
|
6
6
|
interface AuthyonProviderProps<TUser extends User = User> extends SessionControllerOptions {
|
|
7
7
|
client: AuthyonClient;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
3
|
+
import { a1 as User, N as SessionControllerOptions, A as AuthyonClient, U as SessionSnapshot, S as Session, f as AbilitySubject, s as AuthyonAbilityOptions, q as AuthyonAbility } from '../ability-5_xXXbDF.js';
|
|
4
|
+
export { v as AuthyonSessionController, V as SessionSnapshotListener, W as SessionStatus } from '../ability-5_xXXbDF.js';
|
|
5
5
|
|
|
6
6
|
interface AuthyonProviderProps<TUser extends User = User> extends SessionControllerOptions {
|
|
7
7
|
client: AuthyonClient;
|