@aooth/idp 0.1.58 → 0.1.59

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/dist/index.d.cts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Clock } from "@aooth/auth";
2
2
  import { FederatedIdentity, FederatedIdentityStore, FederatedProfileSnapshot, UserService } from "@aooth/user";
3
3
  import { JWTPayload, JWTVerifyGetKey } from "jose";
4
-
5
4
  //#region src/errors.d.ts
6
5
  /**
7
6
  * Federated-login failure taxonomy (RFC IDP.md §8). Mirrors `AuthError` /
@@ -12,7 +11,25 @@ import { JWTPayload, JWTVerifyGetKey } from "jose";
12
11
  * `OAuthController`'s job; this layer only classifies. Messages are deliberately
13
12
  * benign so the controller can surface them without leaking CSRF-vs-expiry.
14
13
  */
15
- type OAuthErrorType = /** `:provider` did not resolve in the registry (→ HTTP 404 in phase 3). */"UNKNOWN_PROVIDER" /** Misconfigured provider/registry (missing clientId, issuer, baseUrl, secret). */ | "INVALID_CONFIG" /** Signed `state` failed signature/binding verification (CSRF). */ | "STATE_INVALID" /** Signed `state` is well-formed but past its TTL — restart `/start`. */ | "STATE_EXPIRED" /** Provider returned `?error=` or the user denied consent. */ | "PROVIDER_DENIED" /** Token-endpoint exchange failed: network, 5xx, malformed body, or `code` reuse. */ | "EXCHANGE_FAILED" /** JWKS / discovery document fetch failed — verification fails CLOSED (§7). */ | "JWKS_FAILED" /** OIDC ID-token failed the OIDC Core 3.1.3.7 validation list (§7). */ | "ID_TOKEN_INVALID" /** Policy needed a verified email but the provider returned none. */ | "EMAIL_UNAVAILABLE";
14
+ type OAuthErrorType =
15
+ /** `:provider` did not resolve in the registry (→ HTTP 404 in phase 3). */
16
+ "UNKNOWN_PROVIDER" |
17
+ /** Misconfigured provider/registry (missing clientId, issuer, baseUrl, secret). */
18
+ "INVALID_CONFIG" |
19
+ /** Signed `state` failed signature/binding verification (CSRF). */
20
+ "STATE_INVALID" |
21
+ /** Signed `state` is well-formed but past its TTL — restart `/start`. */
22
+ "STATE_EXPIRED" |
23
+ /** Provider returned `?error=` or the user denied consent. */
24
+ "PROVIDER_DENIED" |
25
+ /** Token-endpoint exchange failed: network, 5xx, malformed body, or `code` reuse. */
26
+ "EXCHANGE_FAILED" |
27
+ /** JWKS / discovery document fetch failed — verification fails CLOSED (§7). */
28
+ "JWKS_FAILED" |
29
+ /** OIDC ID-token failed the OIDC Core 3.1.3.7 validation list (§7). */
30
+ "ID_TOKEN_INVALID" |
31
+ /** Policy needed a verified email but the provider returned none. */
32
+ "EMAIL_UNAVAILABLE";
16
33
  declare class OAuthError extends Error {
17
34
  readonly type: OAuthErrorType;
18
35
  readonly details?: Record<string, unknown> | undefined;
@@ -127,12 +144,16 @@ declare function isConfigurableProvider(p: IdentityProvider): p is ConfigurableP
127
144
  * How a federated login that matches an existing local account **by email**
128
145
  * is handled (RFC §4 — the account-takeover-sensitive knob).
129
146
  */
130
- type EmailMatchPolicy = /** Never match by email — always create a fresh account. */"create-separate"
147
+ type EmailMatchPolicy =
148
+ /** Never match by email — always create a fresh account. */
149
+ "create-separate" |
131
150
  /**
132
151
  * Auto-link only when the provider's `email_verified === true` AND the
133
152
  * provider is in `trustEmailVerifiedFrom`. A deliberate security downgrade.
134
153
  */
135
- | "auto-link-if-verified" /** Default & safest: surface the candidate; require interactive proof-of-control to link. */ | "require-interactive-link";
154
+ "auto-link-if-verified" |
155
+ /** Default & safest: surface the candidate; require interactive proof-of-control to link. */
156
+ "require-interactive-link";
136
157
  interface FederatedPolicy {
137
158
  /** Default `'require-interactive-link'`. */
138
159
  emailMatch?: EmailMatchPolicy;
@@ -155,22 +176,32 @@ declare function resolveFederatedPolicy(policy?: FederatedPolicy): ResolvedFeder
155
176
  * (`linked`/`created`/`auto-linked`), divert to an interactive link sub-flow
156
177
  * (`needs-link`), or fail soft (`denied`).
157
178
  */
158
- type ResolveOutcome = /** Known `(provider, subject)` → its owning user. */{
179
+ type ResolveOutcome =
180
+ /** Known `(provider, subject)` → its owning user. */
181
+ {
159
182
  kind: "linked";
160
183
  userId: string;
161
184
  isNew: false;
162
- } /** No match → a fresh account was created and linked. */ | {
185
+ } |
186
+ /** No match → a fresh account was created and linked. */
187
+ {
163
188
  kind: "created";
164
189
  userId: string;
165
190
  isNew: true;
166
- } /** Email matched an existing account and policy auto-linked it. */ | {
191
+ } |
192
+ /** Email matched an existing account and policy auto-linked it. */
193
+ {
167
194
  kind: "auto-linked";
168
195
  userId: string;
169
196
  isNew: false;
170
- } /** Email matched an existing account; interactive proof-of-control required to link. */ | {
197
+ } |
198
+ /** Email matched an existing account; interactive proof-of-control required to link. */
199
+ {
171
200
  kind: "needs-link";
172
201
  candidateUserId: string;
173
- } /** Refused: signup disabled with no match, or policy needed an email the provider lacked. */ | {
202
+ } |
203
+ /** Refused: signup disabled with no match, or policy needed an email the provider lacked. */
204
+ {
174
205
  kind: "denied";
175
206
  reason: "signup-disabled" | "email-unavailable";
176
207
  };
package/dist/index.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Clock } from "@aooth/auth";
2
2
  import { JWTPayload, JWTVerifyGetKey } from "jose";
3
3
  import { FederatedIdentity, FederatedIdentityStore, FederatedProfileSnapshot, UserService } from "@aooth/user";
4
-
5
4
  //#region src/errors.d.ts
6
5
  /**
7
6
  * Federated-login failure taxonomy (RFC IDP.md §8). Mirrors `AuthError` /
@@ -12,7 +11,25 @@ import { FederatedIdentity, FederatedIdentityStore, FederatedProfileSnapshot, Us
12
11
  * `OAuthController`'s job; this layer only classifies. Messages are deliberately
13
12
  * benign so the controller can surface them without leaking CSRF-vs-expiry.
14
13
  */
15
- type OAuthErrorType = /** `:provider` did not resolve in the registry (→ HTTP 404 in phase 3). */"UNKNOWN_PROVIDER" /** Misconfigured provider/registry (missing clientId, issuer, baseUrl, secret). */ | "INVALID_CONFIG" /** Signed `state` failed signature/binding verification (CSRF). */ | "STATE_INVALID" /** Signed `state` is well-formed but past its TTL — restart `/start`. */ | "STATE_EXPIRED" /** Provider returned `?error=` or the user denied consent. */ | "PROVIDER_DENIED" /** Token-endpoint exchange failed: network, 5xx, malformed body, or `code` reuse. */ | "EXCHANGE_FAILED" /** JWKS / discovery document fetch failed — verification fails CLOSED (§7). */ | "JWKS_FAILED" /** OIDC ID-token failed the OIDC Core 3.1.3.7 validation list (§7). */ | "ID_TOKEN_INVALID" /** Policy needed a verified email but the provider returned none. */ | "EMAIL_UNAVAILABLE";
14
+ type OAuthErrorType =
15
+ /** `:provider` did not resolve in the registry (→ HTTP 404 in phase 3). */
16
+ "UNKNOWN_PROVIDER" |
17
+ /** Misconfigured provider/registry (missing clientId, issuer, baseUrl, secret). */
18
+ "INVALID_CONFIG" |
19
+ /** Signed `state` failed signature/binding verification (CSRF). */
20
+ "STATE_INVALID" |
21
+ /** Signed `state` is well-formed but past its TTL — restart `/start`. */
22
+ "STATE_EXPIRED" |
23
+ /** Provider returned `?error=` or the user denied consent. */
24
+ "PROVIDER_DENIED" |
25
+ /** Token-endpoint exchange failed: network, 5xx, malformed body, or `code` reuse. */
26
+ "EXCHANGE_FAILED" |
27
+ /** JWKS / discovery document fetch failed — verification fails CLOSED (§7). */
28
+ "JWKS_FAILED" |
29
+ /** OIDC ID-token failed the OIDC Core 3.1.3.7 validation list (§7). */
30
+ "ID_TOKEN_INVALID" |
31
+ /** Policy needed a verified email but the provider returned none. */
32
+ "EMAIL_UNAVAILABLE";
16
33
  declare class OAuthError extends Error {
17
34
  readonly type: OAuthErrorType;
18
35
  readonly details?: Record<string, unknown> | undefined;
@@ -127,12 +144,16 @@ declare function isConfigurableProvider(p: IdentityProvider): p is ConfigurableP
127
144
  * How a federated login that matches an existing local account **by email**
128
145
  * is handled (RFC §4 — the account-takeover-sensitive knob).
129
146
  */
130
- type EmailMatchPolicy = /** Never match by email — always create a fresh account. */"create-separate"
147
+ type EmailMatchPolicy =
148
+ /** Never match by email — always create a fresh account. */
149
+ "create-separate" |
131
150
  /**
132
151
  * Auto-link only when the provider's `email_verified === true` AND the
133
152
  * provider is in `trustEmailVerifiedFrom`. A deliberate security downgrade.
134
153
  */
135
- | "auto-link-if-verified" /** Default & safest: surface the candidate; require interactive proof-of-control to link. */ | "require-interactive-link";
154
+ "auto-link-if-verified" |
155
+ /** Default & safest: surface the candidate; require interactive proof-of-control to link. */
156
+ "require-interactive-link";
136
157
  interface FederatedPolicy {
137
158
  /** Default `'require-interactive-link'`. */
138
159
  emailMatch?: EmailMatchPolicy;
@@ -155,22 +176,32 @@ declare function resolveFederatedPolicy(policy?: FederatedPolicy): ResolvedFeder
155
176
  * (`linked`/`created`/`auto-linked`), divert to an interactive link sub-flow
156
177
  * (`needs-link`), or fail soft (`denied`).
157
178
  */
158
- type ResolveOutcome = /** Known `(provider, subject)` → its owning user. */{
179
+ type ResolveOutcome =
180
+ /** Known `(provider, subject)` → its owning user. */
181
+ {
159
182
  kind: "linked";
160
183
  userId: string;
161
184
  isNew: false;
162
- } /** No match → a fresh account was created and linked. */ | {
185
+ } |
186
+ /** No match → a fresh account was created and linked. */
187
+ {
163
188
  kind: "created";
164
189
  userId: string;
165
190
  isNew: true;
166
- } /** Email matched an existing account and policy auto-linked it. */ | {
191
+ } |
192
+ /** Email matched an existing account and policy auto-linked it. */
193
+ {
167
194
  kind: "auto-linked";
168
195
  userId: string;
169
196
  isNew: false;
170
- } /** Email matched an existing account; interactive proof-of-control required to link. */ | {
197
+ } |
198
+ /** Email matched an existing account; interactive proof-of-control required to link. */
199
+ {
171
200
  kind: "needs-link";
172
201
  candidateUserId: string;
173
- } /** Refused: signup disabled with no match, or policy needed an email the provider lacked. */ | {
202
+ } |
203
+ /** Refused: signup disabled with no match, or policy needed an email the provider lacked. */
204
+ {
174
205
  kind: "denied";
175
206
  reason: "signup-disabled" | "email-unavailable";
176
207
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aooth/idp",
3
- "version": "0.1.58",
3
+ "version": "0.1.59",
4
4
  "description": "Framework-agnostic OAuth2 / OIDC federated-login core for aoothjs (provider registry, PKCE/state, ID-token verification, account resolution)",
5
5
  "keywords": [
6
6
  "aoothjs",
@@ -43,8 +43,8 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "jose": "^6.2.3",
46
- "@aooth/auth": "0.1.58",
47
- "@aooth/user": "0.1.58"
46
+ "@aooth/auth": "0.1.59",
47
+ "@aooth/user": "0.1.59"
48
48
  },
49
49
  "devDependencies": {
50
50
  "vitest": "npm:@voidzero-dev/vite-plus-test@latest"