@dloizides/auth-client 2.0.0 → 3.0.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 +90 -0
- package/README.md +37 -1
- package/dist/{AuthClient-Dim7HPRz.d.ts → AuthClient-BGr8L03W.d.mts} +62 -35
- package/dist/{AuthClient-Dim7HPRz.d.mts → AuthClient-D95OMajD.d.ts} +62 -35
- package/dist/TokenResponse-CY1CaU2l.d.mts +59 -0
- package/dist/TokenResponse-CY1CaU2l.d.ts +59 -0
- package/dist/index.d.mts +109 -28
- package/dist/index.d.ts +109 -28
- package/dist/index.js +329 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +322 -20
- package/dist/index.mjs.map +1 -1
- package/dist/oidc/index.d.mts +127 -0
- package/dist/oidc/index.d.ts +127 -0
- package/dist/oidc/index.js +192 -0
- package/dist/oidc/index.js.map +1 -0
- package/dist/oidc/index.mjs +184 -0
- package/dist/oidc/index.mjs.map +1 -0
- package/dist/react.d.mts +2 -1
- package/dist/react.d.ts +2 -1
- package/package.json +12 -2
package/dist/index.js
CHANGED
|
@@ -159,11 +159,63 @@ var AuthClient = class _AuthClient {
|
|
|
159
159
|
...config,
|
|
160
160
|
scope: config.scope ?? DEFAULT_SCOPE
|
|
161
161
|
};
|
|
162
|
+
this.directKcAuth = config.useDirectKcAuth === true;
|
|
162
163
|
this.tokenStorage = storage;
|
|
163
164
|
this.api = collaborators.api;
|
|
164
165
|
this.interceptor = collaborators.interceptor;
|
|
165
166
|
this.inactivityTracker = collaborators.inactivityTracker;
|
|
166
167
|
this.events = collaborators.events ?? new AuthEventEmitter();
|
|
168
|
+
this.onTokenAcquired = collaborators.onTokenAcquired;
|
|
169
|
+
this.onTokenRefreshed = collaborators.onTokenRefreshed;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Whether this client is configured to route auth flows directly to
|
|
173
|
+
* Keycloak (v2.1.0 direct-KC path) instead of through the proxied
|
|
174
|
+
* identity-api `/auth/*` endpoints.
|
|
175
|
+
*
|
|
176
|
+
* Apps can render conditionally on this — e.g. to swap a login form for
|
|
177
|
+
* a "Sign in with Keycloak" redirect button.
|
|
178
|
+
*/
|
|
179
|
+
isDirectMode() {
|
|
180
|
+
return this.directKcAuth;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Persist a token bundle produced by an external flow (e.g. the
|
|
184
|
+
* app-side `useKeycloakExchange` hook that consumes the shared
|
|
185
|
+
* `exchangeAuthorizationCode` primitive). Fires `onTokenAcquired` after
|
|
186
|
+
* persistence and marks the inactivity tracker active.
|
|
187
|
+
*
|
|
188
|
+
* Designed for the v2.1.0 direct-KC path where the PKCE code exchange
|
|
189
|
+
* happens in the app's React-Query hook (which needs `useDispatch`/etc.)
|
|
190
|
+
* but the token persistence + observability should still flow through
|
|
191
|
+
* the shared client.
|
|
192
|
+
*/
|
|
193
|
+
async acceptDirectKcTokens(response) {
|
|
194
|
+
const tokens = tokenResponseToAuthTokens(response);
|
|
195
|
+
await this.tokenStorage.write(tokens);
|
|
196
|
+
if (this.inactivityTracker !== void 0) {
|
|
197
|
+
await this.inactivityTracker.markActive();
|
|
198
|
+
}
|
|
199
|
+
if (this.onTokenAcquired !== void 0) {
|
|
200
|
+
this.onTokenAcquired(tokens);
|
|
201
|
+
}
|
|
202
|
+
return tokens;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Same as {@link acceptDirectKcTokens} but fires `onTokenRefreshed`.
|
|
206
|
+
* Use after a `refreshAccessToken()` swap to keep observability counts
|
|
207
|
+
* separated between "fresh login" and "silent refresh".
|
|
208
|
+
*/
|
|
209
|
+
async acceptDirectKcRefresh(response) {
|
|
210
|
+
const tokens = tokenResponseToAuthTokens(response);
|
|
211
|
+
await this.tokenStorage.write(tokens);
|
|
212
|
+
if (this.inactivityTracker !== void 0) {
|
|
213
|
+
await this.inactivityTracker.markActive();
|
|
214
|
+
}
|
|
215
|
+
if (this.onTokenRefreshed !== void 0) {
|
|
216
|
+
this.onTokenRefreshed(tokens);
|
|
217
|
+
}
|
|
218
|
+
return tokens;
|
|
167
219
|
}
|
|
168
220
|
/**
|
|
169
221
|
* Build an {@link AuthClient} from a standalone issuer URL by parsing the
|
|
@@ -308,7 +360,11 @@ var AuthClient = class _AuthClient {
|
|
|
308
360
|
if (this.interceptor === void 0) {
|
|
309
361
|
throw new Error("AuthClient.refresh: no RefreshInterceptor configured");
|
|
310
362
|
}
|
|
311
|
-
|
|
363
|
+
const tokens = await this.interceptor.refreshTokens();
|
|
364
|
+
if (tokens !== null && this.onTokenRefreshed !== void 0) {
|
|
365
|
+
this.onTokenRefreshed(tokens);
|
|
366
|
+
}
|
|
367
|
+
return tokens;
|
|
312
368
|
}
|
|
313
369
|
async loginWithOtp(input) {
|
|
314
370
|
return this.runLogin(this.requireApi().loginWithOtp({
|
|
@@ -355,6 +411,9 @@ var AuthClient = class _AuthClient {
|
|
|
355
411
|
if (this.inactivityTracker !== void 0) {
|
|
356
412
|
await this.inactivityTracker.markActive();
|
|
357
413
|
}
|
|
414
|
+
if (this.onTokenAcquired !== void 0) {
|
|
415
|
+
this.onTokenAcquired(tokens);
|
|
416
|
+
}
|
|
358
417
|
return tokens;
|
|
359
418
|
}
|
|
360
419
|
requireApi() {
|
|
@@ -374,6 +433,152 @@ var AuthClient = class _AuthClient {
|
|
|
374
433
|
}
|
|
375
434
|
};
|
|
376
435
|
|
|
436
|
+
// src/oidc/discovery.ts
|
|
437
|
+
var cache = /* @__PURE__ */ new Map();
|
|
438
|
+
function normalizeIssuer(issuerUrl) {
|
|
439
|
+
return issuerUrl.replace(/\/$/, "");
|
|
440
|
+
}
|
|
441
|
+
function isOidcDiscoveryDocument(data) {
|
|
442
|
+
if (data === null || typeof data !== "object") {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
const d = data;
|
|
446
|
+
return typeof d.issuer === "string" && d.issuer !== "" && typeof d.authorization_endpoint === "string" && d.authorization_endpoint !== "" && typeof d.token_endpoint === "string" && d.token_endpoint !== "";
|
|
447
|
+
}
|
|
448
|
+
async function fetchDiscoveryDocument(input) {
|
|
449
|
+
const key = normalizeIssuer(input.issuerUrl);
|
|
450
|
+
const cached = cache.get(key);
|
|
451
|
+
if (cached !== void 0) {
|
|
452
|
+
return cached;
|
|
453
|
+
}
|
|
454
|
+
const response = await input.http({
|
|
455
|
+
url: `${key}/.well-known/openid-configuration`,
|
|
456
|
+
method: "GET"
|
|
457
|
+
});
|
|
458
|
+
if (!response.ok) {
|
|
459
|
+
throw new Error(
|
|
460
|
+
`OIDC discovery failed: ${String(response.status)} for ${key}`
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
if (!isOidcDiscoveryDocument(response.data)) {
|
|
464
|
+
throw new Error(`OIDC discovery returned invalid metadata for ${key}`);
|
|
465
|
+
}
|
|
466
|
+
cache.set(key, response.data);
|
|
467
|
+
return response.data;
|
|
468
|
+
}
|
|
469
|
+
function clearDiscoveryCache() {
|
|
470
|
+
cache.clear();
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/oidc/pkce.ts
|
|
474
|
+
var VERIFIER_MIN_LENGTH = 43;
|
|
475
|
+
var VERIFIER_MAX_LENGTH = 128;
|
|
476
|
+
var DEFAULT_VERIFIER_LENGTH = 64;
|
|
477
|
+
var RANDOM_BYTES_PER_CHAR = 1;
|
|
478
|
+
var UNRESERVED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
479
|
+
function getCrypto() {
|
|
480
|
+
const c = globalThis.crypto;
|
|
481
|
+
if (c === void 0 || c.subtle === void 0) {
|
|
482
|
+
throw new Error("pkce: globalThis.crypto.subtle is required (Node 16+ / modern browser)");
|
|
483
|
+
}
|
|
484
|
+
return c;
|
|
485
|
+
}
|
|
486
|
+
function assertVerifierLength(length) {
|
|
487
|
+
if (length < VERIFIER_MIN_LENGTH || length > VERIFIER_MAX_LENGTH) {
|
|
488
|
+
throw new Error(`pkce: code_verifier length must be ${String(VERIFIER_MIN_LENGTH)}-${String(VERIFIER_MAX_LENGTH)} chars (RFC 7636)`);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function base64UrlEncode(buffer) {
|
|
492
|
+
const bytes = new Uint8Array(buffer);
|
|
493
|
+
let binary = "";
|
|
494
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
495
|
+
binary += String.fromCharCode(bytes[i]);
|
|
496
|
+
}
|
|
497
|
+
const b64 = globalThis.btoa?.(binary) ?? Buffer.from(binary, "binary").toString("base64");
|
|
498
|
+
let end = b64.length;
|
|
499
|
+
while (end > 0 && b64.charCodeAt(end - 1) === "=".charCodeAt(0)) {
|
|
500
|
+
end -= 1;
|
|
501
|
+
}
|
|
502
|
+
return b64.slice(0, end).replace(/\+/g, "-").replace(/\//g, "_");
|
|
503
|
+
}
|
|
504
|
+
function generateCodeVerifier(length = DEFAULT_VERIFIER_LENGTH) {
|
|
505
|
+
assertVerifierLength(length);
|
|
506
|
+
const crypto = getCrypto();
|
|
507
|
+
const bytes = new Uint8Array(length * RANDOM_BYTES_PER_CHAR);
|
|
508
|
+
crypto.getRandomValues(bytes);
|
|
509
|
+
let out = "";
|
|
510
|
+
for (let i = 0; i < length; i++) {
|
|
511
|
+
const byte = bytes[i];
|
|
512
|
+
out += UNRESERVED_CHARS[byte % UNRESERVED_CHARS.length];
|
|
513
|
+
}
|
|
514
|
+
return out;
|
|
515
|
+
}
|
|
516
|
+
async function deriveCodeChallenge(verifier) {
|
|
517
|
+
assertVerifierLength(verifier.length);
|
|
518
|
+
const crypto = getCrypto();
|
|
519
|
+
const data = new TextEncoder().encode(verifier);
|
|
520
|
+
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
521
|
+
return base64UrlEncode(digest);
|
|
522
|
+
}
|
|
523
|
+
async function generatePkcePair(length) {
|
|
524
|
+
const codeVerifier = generateCodeVerifier(length);
|
|
525
|
+
const codeChallenge = await deriveCodeChallenge(codeVerifier);
|
|
526
|
+
return { codeVerifier, codeChallenge, codeChallengeMethod: "S256" };
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/utils/buildTokenRequestBody.ts
|
|
530
|
+
function buildAuthorizationCodeBody(input) {
|
|
531
|
+
return new URLSearchParams({
|
|
532
|
+
client_id: input.clientId,
|
|
533
|
+
grant_type: "authorization_code",
|
|
534
|
+
code: input.code,
|
|
535
|
+
redirect_uri: input.redirectUri,
|
|
536
|
+
code_verifier: input.codeVerifier
|
|
537
|
+
}).toString();
|
|
538
|
+
}
|
|
539
|
+
function buildRefreshTokenBody(input) {
|
|
540
|
+
return new URLSearchParams({
|
|
541
|
+
client_id: input.clientId,
|
|
542
|
+
grant_type: "refresh_token",
|
|
543
|
+
refresh_token: input.refreshToken
|
|
544
|
+
}).toString();
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/oidc/tokenExchange.ts
|
|
548
|
+
var FORM_HEADERS = {
|
|
549
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
550
|
+
};
|
|
551
|
+
async function postTokenEndpoint(http, url, body) {
|
|
552
|
+
const response = await http({
|
|
553
|
+
url,
|
|
554
|
+
method: "POST",
|
|
555
|
+
headers: FORM_HEADERS,
|
|
556
|
+
body
|
|
557
|
+
});
|
|
558
|
+
if (!response.ok) {
|
|
559
|
+
throw new Error(`token endpoint POST failed: ${String(response.status)}`);
|
|
560
|
+
}
|
|
561
|
+
return normalizeTokenResponse(response.data);
|
|
562
|
+
}
|
|
563
|
+
async function exchangeAuthorizationCode(input) {
|
|
564
|
+
const url = buildTokenEndpoint(input.baseUrl, input.realm);
|
|
565
|
+
const body = buildAuthorizationCodeBody({
|
|
566
|
+
clientId: input.clientId,
|
|
567
|
+
code: input.code,
|
|
568
|
+
redirectUri: input.redirectUri,
|
|
569
|
+
codeVerifier: input.codeVerifier
|
|
570
|
+
});
|
|
571
|
+
return postTokenEndpoint(input.http, url, body);
|
|
572
|
+
}
|
|
573
|
+
async function refreshAccessToken(input) {
|
|
574
|
+
const url = buildTokenEndpoint(input.baseUrl, input.realm);
|
|
575
|
+
const body = buildRefreshTokenBody({
|
|
576
|
+
clientId: input.clientId,
|
|
577
|
+
refreshToken: input.refreshToken
|
|
578
|
+
});
|
|
579
|
+
return postTokenEndpoint(input.http, url, body);
|
|
580
|
+
}
|
|
581
|
+
|
|
377
582
|
// src/types/KeycloakRoles.ts
|
|
378
583
|
var KeycloakRoles = /* @__PURE__ */ ((KeycloakRoles2) => {
|
|
379
584
|
KeycloakRoles2["SuperUser"] = "superUser";
|
|
@@ -854,6 +1059,121 @@ var AuthApiClient = class {
|
|
|
854
1059
|
}
|
|
855
1060
|
};
|
|
856
1061
|
|
|
1062
|
+
// src/bff/BffAuthClient.ts
|
|
1063
|
+
var CSRF_HEADER = "X-BFF-Csrf";
|
|
1064
|
+
var CSRF_HEADER_VALUE = "1";
|
|
1065
|
+
var JSON_CONTENT_TYPE = "application/json";
|
|
1066
|
+
var ENDPOINTS = {
|
|
1067
|
+
login: "/bff/login",
|
|
1068
|
+
logout: "/bff/logout",
|
|
1069
|
+
me: "/bff/me",
|
|
1070
|
+
register: "/bff/register",
|
|
1071
|
+
forgotPassword: "/bff/forgot-password",
|
|
1072
|
+
resetPassword: "/bff/reset-password"
|
|
1073
|
+
};
|
|
1074
|
+
function isRecord(value) {
|
|
1075
|
+
return typeof value === "object" && value !== null;
|
|
1076
|
+
}
|
|
1077
|
+
function extractUser(data) {
|
|
1078
|
+
if (!isRecord(data)) {
|
|
1079
|
+
return null;
|
|
1080
|
+
}
|
|
1081
|
+
const envelope = data;
|
|
1082
|
+
return isRecord(envelope.user) ? envelope.user : null;
|
|
1083
|
+
}
|
|
1084
|
+
var BffAuthClient = class {
|
|
1085
|
+
constructor(options) {
|
|
1086
|
+
this.http = options.http;
|
|
1087
|
+
this.baseUrl = (options.baseUrl ?? "").replace(/\/$/, "");
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* `POST /bff/login` — the BFF does ROPC against Keycloak server-side, stores
|
|
1091
|
+
* the tokens in its Redis vault, and sets the httpOnly session cookie.
|
|
1092
|
+
* Returns the sanitised user. Throws on a non-2xx response.
|
|
1093
|
+
*/
|
|
1094
|
+
async login(request) {
|
|
1095
|
+
const data = await this.postState(ENDPOINTS.login, request, "login");
|
|
1096
|
+
const user = extractUser(data);
|
|
1097
|
+
if (user === null) {
|
|
1098
|
+
throw new Error("login: BFF response missing user");
|
|
1099
|
+
}
|
|
1100
|
+
return user;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* `POST /bff/logout` — the BFF calls KC end-session, deletes the Redis
|
|
1104
|
+
* session, and clears the cookie. Non-fatal: a failed logout still leaves
|
|
1105
|
+
* the SPA logged out client-side. Throws only on a non-2xx response.
|
|
1106
|
+
*/
|
|
1107
|
+
async logout() {
|
|
1108
|
+
await this.postState(ENDPOINTS.logout, void 0, "logout");
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* `GET /bff/me` — the live session's sanitised user, or `null` when there is
|
|
1112
|
+
* no session (the BFF answers `401`). Used at app load to bootstrap auth
|
|
1113
|
+
* state in place of the old token-in-storage check.
|
|
1114
|
+
*/
|
|
1115
|
+
async getCurrentUser() {
|
|
1116
|
+
const response = await this.http({
|
|
1117
|
+
url: `${this.baseUrl}${ENDPOINTS.me}`,
|
|
1118
|
+
method: "GET",
|
|
1119
|
+
headers: { Accept: JSON_CONTENT_TYPE },
|
|
1120
|
+
credentials: "include"
|
|
1121
|
+
});
|
|
1122
|
+
if (!response.ok) {
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
return extractUser(response.data);
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* `POST /bff/register` — the BFF proxies registration to TenantService and,
|
|
1129
|
+
* on success, establishes a session exactly like `login`. Returns the user.
|
|
1130
|
+
*/
|
|
1131
|
+
async register(request) {
|
|
1132
|
+
const data = await this.postState(ENDPOINTS.register, request, "register");
|
|
1133
|
+
const user = extractUser(data);
|
|
1134
|
+
if (user === null) {
|
|
1135
|
+
throw new Error("register: BFF response missing user");
|
|
1136
|
+
}
|
|
1137
|
+
return user;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* `POST /bff/forgot-password` — proxied to TenantService. The backend
|
|
1141
|
+
* returns 200 unconditionally (no email enumeration); anything else throws.
|
|
1142
|
+
*/
|
|
1143
|
+
async forgotPassword(request) {
|
|
1144
|
+
await this.postState(ENDPOINTS.forgotPassword, request, "forgot-password");
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* `POST /bff/reset-password` — proxied to TenantService. Throws on a non-2xx
|
|
1148
|
+
* response (e.g. `400` for an invalid / expired token).
|
|
1149
|
+
*/
|
|
1150
|
+
async resetPassword(request) {
|
|
1151
|
+
await this.postState(ENDPOINTS.resetPassword, request, "reset-password");
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Shared POST for every state-changing `/bff/*` call: same-origin, cookie
|
|
1155
|
+
* included, `X-BFF-Csrf` header attached. Throws a labelled error on non-2xx.
|
|
1156
|
+
*/
|
|
1157
|
+
async postState(path, body, label) {
|
|
1158
|
+
const headers = {
|
|
1159
|
+
"Content-Type": JSON_CONTENT_TYPE,
|
|
1160
|
+
Accept: JSON_CONTENT_TYPE,
|
|
1161
|
+
[CSRF_HEADER]: CSRF_HEADER_VALUE
|
|
1162
|
+
};
|
|
1163
|
+
const response = await this.http({
|
|
1164
|
+
url: `${this.baseUrl}${path}`,
|
|
1165
|
+
method: "POST",
|
|
1166
|
+
headers,
|
|
1167
|
+
body: body === void 0 ? void 0 : JSON.stringify(body),
|
|
1168
|
+
credentials: "include"
|
|
1169
|
+
});
|
|
1170
|
+
if (!response.ok) {
|
|
1171
|
+
throw new Error(`${label} failed with status ${String(response.status)}`);
|
|
1172
|
+
}
|
|
1173
|
+
return response.data;
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
|
|
857
1177
|
// src/utils/normalizeKeycloakUser.ts
|
|
858
1178
|
function isNonEmptyString(value) {
|
|
859
1179
|
return typeof value === "string" && value !== "";
|
|
@@ -904,24 +1224,6 @@ function normalizeKeycloakUser(u) {
|
|
|
904
1224
|
};
|
|
905
1225
|
}
|
|
906
1226
|
|
|
907
|
-
// src/utils/buildTokenRequestBody.ts
|
|
908
|
-
function buildAuthorizationCodeBody(input) {
|
|
909
|
-
return new URLSearchParams({
|
|
910
|
-
client_id: input.clientId,
|
|
911
|
-
grant_type: "authorization_code",
|
|
912
|
-
code: input.code,
|
|
913
|
-
redirect_uri: input.redirectUri,
|
|
914
|
-
code_verifier: input.codeVerifier
|
|
915
|
-
}).toString();
|
|
916
|
-
}
|
|
917
|
-
function buildRefreshTokenBody(input) {
|
|
918
|
-
return new URLSearchParams({
|
|
919
|
-
client_id: input.clientId,
|
|
920
|
-
grant_type: "refresh_token",
|
|
921
|
-
refresh_token: input.refreshToken
|
|
922
|
-
}).toString();
|
|
923
|
-
}
|
|
924
|
-
|
|
925
1227
|
// src/utils/extractAuthCode.ts
|
|
926
1228
|
function extractAuthCode(response) {
|
|
927
1229
|
if (!response) {
|
|
@@ -985,6 +1287,7 @@ function decodeUtf8(binary) {
|
|
|
985
1287
|
exports.AuthApiClient = AuthApiClient;
|
|
986
1288
|
exports.AuthClient = AuthClient;
|
|
987
1289
|
exports.AuthEventEmitter = AuthEventEmitter;
|
|
1290
|
+
exports.BffAuthClient = BffAuthClient;
|
|
988
1291
|
exports.BiometricGate = BiometricGate;
|
|
989
1292
|
exports.BrowserStorageTokenStorage = BrowserStorageTokenStorage;
|
|
990
1293
|
exports.CookieTokenStorage = CookieTokenStorage;
|
|
@@ -1001,16 +1304,23 @@ exports.buildLogoutEndpoint = buildLogoutEndpoint;
|
|
|
1001
1304
|
exports.buildRefreshTokenBody = buildRefreshTokenBody;
|
|
1002
1305
|
exports.buildTokenEndpoint = buildTokenEndpoint;
|
|
1003
1306
|
exports.buildUserInfoEndpoint = buildUserInfoEndpoint;
|
|
1307
|
+
exports.clearDiscoveryCache = clearDiscoveryCache;
|
|
1004
1308
|
exports.computeExpiresAt = computeExpiresAt;
|
|
1005
1309
|
exports.createFetchHttpClient = createFetchHttpClient;
|
|
1006
1310
|
exports.decodeJwt = decodeJwt;
|
|
1311
|
+
exports.deriveCodeChallenge = deriveCodeChallenge;
|
|
1312
|
+
exports.exchangeAuthorizationCode = exchangeAuthorizationCode;
|
|
1007
1313
|
exports.extractAuthCode = extractAuthCode;
|
|
1314
|
+
exports.fetchDiscoveryDocument = fetchDiscoveryDocument;
|
|
1315
|
+
exports.generateCodeVerifier = generateCodeVerifier;
|
|
1316
|
+
exports.generatePkcePair = generatePkcePair;
|
|
1008
1317
|
exports.isKeycloakRole = isKeycloakRole;
|
|
1009
1318
|
exports.isTokenExpired = isTokenExpired;
|
|
1010
1319
|
exports.normalizeKeycloakUser = normalizeKeycloakUser;
|
|
1011
1320
|
exports.normalizeTokenResponse = normalizeTokenResponse;
|
|
1012
1321
|
exports.parseBaseUrlFromIssuer = parseBaseUrlFromIssuer;
|
|
1013
1322
|
exports.parseRealmFromIssuer = parseRealmFromIssuer;
|
|
1323
|
+
exports.refreshAccessToken = refreshAccessToken;
|
|
1014
1324
|
exports.tokenResponseToAuthTokens = tokenResponseToAuthTokens;
|
|
1015
1325
|
//# sourceMappingURL=index.js.map
|
|
1016
1326
|
//# sourceMappingURL=index.js.map
|