@synqauth/js 0.0.0 → 0.2.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/dist/api-CeYAjkvX.js +467 -0
- package/dist/index.d.ts +392 -232
- package/dist/index.js +90 -5
- package/dist/{management-y9-9AIc-.d.ts → management-CWdCiiEv.d.ts} +668 -10
- package/dist/server.d.ts +108 -2
- package/dist/server.js +122 -2
- package/package.json +1 -1
- package/dist/api-Cf9K1Rc9.js +0 -163
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as problemError, i as
|
|
1
|
+
import { a as readSavedSignIn, c as problemError, i as newSignIn, l as toSynqError, n as secureUrl, o as SynqError, r as SignInFlow, s as isSynqError, t as createApiClient } from "./api-CeYAjkvX.js";
|
|
2
2
|
import * as oauth from "oauth4webapi";
|
|
3
3
|
//#region src/storage.ts
|
|
4
4
|
/**
|
|
@@ -159,6 +159,7 @@ var Client = class {
|
|
|
159
159
|
redirectUri: this.#options.redirectUri,
|
|
160
160
|
resource: options.resource ?? this.#options.resource,
|
|
161
161
|
maxAge: options.maxAge,
|
|
162
|
+
...options.acr?.essential ? { acr: [...options.acr.values] } : {},
|
|
162
163
|
createdAt: now()
|
|
163
164
|
};
|
|
164
165
|
const url = new URL(server.authorization_endpoint);
|
|
@@ -181,6 +182,15 @@ var Client = class {
|
|
|
181
182
|
if (options.maxAge !== void 0) params.set("max_age", String(options.maxAge));
|
|
182
183
|
if (options.loginHint) params.set("login_hint", options.loginHint);
|
|
183
184
|
if (options.method) params.set("synq_method", options.method);
|
|
185
|
+
if (options.acr) {
|
|
186
|
+
if (options.acr.values.length === 0) throw new SynqError("invalid_options", "acr needs at least one value");
|
|
187
|
+
if (params.has("acr_values") || params.has("claims")) throw new SynqError("invalid_options", "acr_values and claims come from the acr option");
|
|
188
|
+
if (options.acr.essential) params.set("claims", JSON.stringify({ id_token: { acr: {
|
|
189
|
+
essential: true,
|
|
190
|
+
values: [...options.acr.values]
|
|
191
|
+
} } }));
|
|
192
|
+
else params.set("acr_values", options.acr.values.join(" "));
|
|
193
|
+
}
|
|
184
194
|
await this.#transactions.set(TRANSACTION_PREFIX + transaction.state, JSON.stringify(transaction));
|
|
185
195
|
if (!options.pushed) return url;
|
|
186
196
|
if (!server.pushed_authorization_request_endpoint) throw new SynqError("discovery_failed", "The issuer takes no pushed authorization requests");
|
|
@@ -224,6 +234,7 @@ var Client = class {
|
|
|
224
234
|
requireIdToken: true
|
|
225
235
|
});
|
|
226
236
|
const claims = oauth.getValidatedIdTokenClaims(result);
|
|
237
|
+
if (transaction.acr && !(claims?.acr && transaction.acr.includes(claims.acr))) throw new SynqError("unmet_authentication_requirements", "The sign-in did not reach the level this app requires");
|
|
227
238
|
this.#generation += 1;
|
|
228
239
|
await this.#clear();
|
|
229
240
|
const session = await this.#save(result, claims);
|
|
@@ -271,6 +282,39 @@ var Client = class {
|
|
|
271
282
|
this.#listeners.delete(listener);
|
|
272
283
|
};
|
|
273
284
|
}
|
|
285
|
+
startSignIn({ endUserIp, ...options } = {}) {
|
|
286
|
+
return new SignInFlow(this.#signInPort(endUserIp), newSignIn(options.scope ?? this.#options.scope ?? "openid", {
|
|
287
|
+
...options,
|
|
288
|
+
resource: options.resource ?? this.#options.resource
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
resumeSignIn(saved, options = {}) {
|
|
292
|
+
return new SignInFlow(this.#signInPort(options.endUserIp), readSavedSignIn(saved));
|
|
293
|
+
}
|
|
294
|
+
/** What a flow needs of this client: its issuer, its credentials, and keeping the session. */
|
|
295
|
+
#signInPort(endUserIp) {
|
|
296
|
+
return {
|
|
297
|
+
...endUserIp ? { headers: { "synq-end-user-ip": endUserIp } } : {},
|
|
298
|
+
server: () => this.#discover(),
|
|
299
|
+
client: this.#client,
|
|
300
|
+
auth: this.#auth,
|
|
301
|
+
fetch: this.#options.fetch ?? globalThis.fetch.bind(globalThis),
|
|
302
|
+
finish: async (result, claims) => {
|
|
303
|
+
this.#generation += 1;
|
|
304
|
+
await this.#clear();
|
|
305
|
+
const session = await this.#save(result, claims, void 0, "app");
|
|
306
|
+
this.#emit({
|
|
307
|
+
type: "signed-in",
|
|
308
|
+
session
|
|
309
|
+
});
|
|
310
|
+
return session;
|
|
311
|
+
},
|
|
312
|
+
hosted: (options) => this.signIn({
|
|
313
|
+
...options.method ? { method: options.method } : {},
|
|
314
|
+
...options.loginHint ? { loginHint: options.loginHint } : {}
|
|
315
|
+
})
|
|
316
|
+
};
|
|
317
|
+
}
|
|
274
318
|
async signOut(options = {}) {
|
|
275
319
|
const stored = await this.#load();
|
|
276
320
|
const refreshToken = await this.#readRefreshToken();
|
|
@@ -291,7 +335,7 @@ var Client = class {
|
|
|
291
335
|
} catch (error) {
|
|
292
336
|
if (attempt === 2) console.warn("@synqauth/js: revoking the refresh token at sign-out failed; it stays usable until it expires", toSynqError(error).code);
|
|
293
337
|
}
|
|
294
|
-
if (!server.end_session_endpoint) return null;
|
|
338
|
+
if (!server.end_session_endpoint || stored?.via === "app") return null;
|
|
295
339
|
const url = new URL(server.end_session_endpoint);
|
|
296
340
|
url.searchParams.set("client_id", this.#options.clientId);
|
|
297
341
|
if (stored?.idToken) url.searchParams.set("id_token_hint", stored.idToken);
|
|
@@ -394,14 +438,15 @@ var Client = class {
|
|
|
394
438
|
})();
|
|
395
439
|
return this.#server;
|
|
396
440
|
}
|
|
397
|
-
async #save(result, claims, previous) {
|
|
441
|
+
async #save(result, claims, previous, via = previous?.via ?? "hosted") {
|
|
398
442
|
const stored = {
|
|
399
443
|
accessToken: result.access_token,
|
|
400
444
|
tokenType: result.token_type,
|
|
401
445
|
expiresAt: result.expires_in === void 0 ? void 0 : now() + result.expires_in,
|
|
402
446
|
scope: result.scope ?? previous?.scope,
|
|
403
447
|
idToken: result.id_token ?? previous?.idToken,
|
|
404
|
-
claims
|
|
448
|
+
claims,
|
|
449
|
+
via
|
|
405
450
|
};
|
|
406
451
|
this.#session = stored;
|
|
407
452
|
await this.#storage.set(SESSION_KEY, JSON.stringify(stored));
|
|
@@ -432,6 +477,7 @@ var Client = class {
|
|
|
432
477
|
async #public(stored) {
|
|
433
478
|
return {
|
|
434
479
|
...stored,
|
|
480
|
+
via: stored.via ?? "hosted",
|
|
435
481
|
refreshable: await this.#readRefreshToken() !== void 0
|
|
436
482
|
};
|
|
437
483
|
}
|
|
@@ -534,6 +580,12 @@ function createAccountClient(options) {
|
|
|
534
580
|
list: (opts) => list("/v1/consents", opts),
|
|
535
581
|
withdraw: (consent, opts) => change("delete", "/v1/consents/{consent}", opts, { path: { consent } })
|
|
536
582
|
},
|
|
583
|
+
apiKeys: {
|
|
584
|
+
apis: (opts) => list("/v1/apis", opts),
|
|
585
|
+
list: (opts) => list("/v1/api-keys", opts),
|
|
586
|
+
create: (input, opts) => change("post", "/v1/api-keys", opts, { body: input }),
|
|
587
|
+
revoke: (key, opts) => change("delete", "/v1/api-keys/{key}", opts, { path: { key } })
|
|
588
|
+
},
|
|
537
589
|
activity: (opts) => list("/v1/sign-ins", opts),
|
|
538
590
|
deletion: {
|
|
539
591
|
schedule: (opts) => change("post", "/v1/deletion", opts),
|
|
@@ -542,6 +594,37 @@ function createAccountClient(options) {
|
|
|
542
594
|
};
|
|
543
595
|
}
|
|
544
596
|
//#endregion
|
|
597
|
+
//#region src/generated/challenge.ts
|
|
598
|
+
/** The ways in an app's own screens sign people in with (`synq_method`). */
|
|
599
|
+
const CHALLENGE_METHODS = [
|
|
600
|
+
"password",
|
|
601
|
+
"email",
|
|
602
|
+
"passkey"
|
|
603
|
+
];
|
|
604
|
+
/** What went wrong with a step (`synq_problem`): branch on it, never on the English. */
|
|
605
|
+
const CHALLENGE_PROBLEMS = [
|
|
606
|
+
"missing",
|
|
607
|
+
"invalid_email",
|
|
608
|
+
"wrong_credentials",
|
|
609
|
+
"email_taken",
|
|
610
|
+
"password_too_short",
|
|
611
|
+
"password_too_long",
|
|
612
|
+
"password_guessable",
|
|
613
|
+
"password_breached",
|
|
614
|
+
"wrong_code",
|
|
615
|
+
"code_expired",
|
|
616
|
+
"code_used_up",
|
|
617
|
+
"address_suppressed",
|
|
618
|
+
"team_only",
|
|
619
|
+
"send_failed",
|
|
620
|
+
"passkey_failed",
|
|
621
|
+
"passkey_unknown",
|
|
622
|
+
"passkey_expired",
|
|
623
|
+
"slow_down",
|
|
624
|
+
"locked",
|
|
625
|
+
"limited"
|
|
626
|
+
];
|
|
627
|
+
//#endregion
|
|
545
628
|
//#region src/generated/errors.ts
|
|
546
629
|
/** Each `code` a Synq API's problem documents carry, with its HTTP status. */
|
|
547
630
|
const ERROR_CODES = {
|
|
@@ -597,9 +680,11 @@ const ERROR_CODES = {
|
|
|
597
680
|
upload_expired: 410,
|
|
598
681
|
file_rejected: 422,
|
|
599
682
|
upload_limit_reached: 409,
|
|
683
|
+
api_keys_not_allowed: 403,
|
|
684
|
+
api_key_limit_reached: 409,
|
|
600
685
|
rate_limited: 429,
|
|
601
686
|
internal_error: 500,
|
|
602
687
|
service_unavailable: 503
|
|
603
688
|
};
|
|
604
689
|
//#endregion
|
|
605
|
-
export { ERROR_CODES, SynqError, accountApiUrl, browserLocalStorage, browserSessionStorage, createAccountClient, createSynqClient, isSynqError, linkSignIn, memoryStorage, problemError };
|
|
690
|
+
export { CHALLENGE_METHODS, CHALLENGE_PROBLEMS, ERROR_CODES, SignInFlow, SynqError, accountApiUrl, browserLocalStorage, browserSessionStorage, createAccountClient, createSynqClient, isSynqError, linkSignIn, memoryStorage, problemError };
|