@dloizides/auth-client 2.1.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/dist/index.mjs CHANGED
@@ -1057,6 +1057,121 @@ var AuthApiClient = class {
1057
1057
  }
1058
1058
  };
1059
1059
 
1060
+ // src/bff/BffAuthClient.ts
1061
+ var CSRF_HEADER = "X-BFF-Csrf";
1062
+ var CSRF_HEADER_VALUE = "1";
1063
+ var JSON_CONTENT_TYPE = "application/json";
1064
+ var ENDPOINTS = {
1065
+ login: "/bff/login",
1066
+ logout: "/bff/logout",
1067
+ me: "/bff/me",
1068
+ register: "/bff/register",
1069
+ forgotPassword: "/bff/forgot-password",
1070
+ resetPassword: "/bff/reset-password"
1071
+ };
1072
+ function isRecord(value) {
1073
+ return typeof value === "object" && value !== null;
1074
+ }
1075
+ function extractUser(data) {
1076
+ if (!isRecord(data)) {
1077
+ return null;
1078
+ }
1079
+ const envelope = data;
1080
+ return isRecord(envelope.user) ? envelope.user : null;
1081
+ }
1082
+ var BffAuthClient = class {
1083
+ constructor(options) {
1084
+ this.http = options.http;
1085
+ this.baseUrl = (options.baseUrl ?? "").replace(/\/$/, "");
1086
+ }
1087
+ /**
1088
+ * `POST /bff/login` — the BFF does ROPC against Keycloak server-side, stores
1089
+ * the tokens in its Redis vault, and sets the httpOnly session cookie.
1090
+ * Returns the sanitised user. Throws on a non-2xx response.
1091
+ */
1092
+ async login(request) {
1093
+ const data = await this.postState(ENDPOINTS.login, request, "login");
1094
+ const user = extractUser(data);
1095
+ if (user === null) {
1096
+ throw new Error("login: BFF response missing user");
1097
+ }
1098
+ return user;
1099
+ }
1100
+ /**
1101
+ * `POST /bff/logout` — the BFF calls KC end-session, deletes the Redis
1102
+ * session, and clears the cookie. Non-fatal: a failed logout still leaves
1103
+ * the SPA logged out client-side. Throws only on a non-2xx response.
1104
+ */
1105
+ async logout() {
1106
+ await this.postState(ENDPOINTS.logout, void 0, "logout");
1107
+ }
1108
+ /**
1109
+ * `GET /bff/me` — the live session's sanitised user, or `null` when there is
1110
+ * no session (the BFF answers `401`). Used at app load to bootstrap auth
1111
+ * state in place of the old token-in-storage check.
1112
+ */
1113
+ async getCurrentUser() {
1114
+ const response = await this.http({
1115
+ url: `${this.baseUrl}${ENDPOINTS.me}`,
1116
+ method: "GET",
1117
+ headers: { Accept: JSON_CONTENT_TYPE },
1118
+ credentials: "include"
1119
+ });
1120
+ if (!response.ok) {
1121
+ return null;
1122
+ }
1123
+ return extractUser(response.data);
1124
+ }
1125
+ /**
1126
+ * `POST /bff/register` — the BFF proxies registration to TenantService and,
1127
+ * on success, establishes a session exactly like `login`. Returns the user.
1128
+ */
1129
+ async register(request) {
1130
+ const data = await this.postState(ENDPOINTS.register, request, "register");
1131
+ const user = extractUser(data);
1132
+ if (user === null) {
1133
+ throw new Error("register: BFF response missing user");
1134
+ }
1135
+ return user;
1136
+ }
1137
+ /**
1138
+ * `POST /bff/forgot-password` — proxied to TenantService. The backend
1139
+ * returns 200 unconditionally (no email enumeration); anything else throws.
1140
+ */
1141
+ async forgotPassword(request) {
1142
+ await this.postState(ENDPOINTS.forgotPassword, request, "forgot-password");
1143
+ }
1144
+ /**
1145
+ * `POST /bff/reset-password` — proxied to TenantService. Throws on a non-2xx
1146
+ * response (e.g. `400` for an invalid / expired token).
1147
+ */
1148
+ async resetPassword(request) {
1149
+ await this.postState(ENDPOINTS.resetPassword, request, "reset-password");
1150
+ }
1151
+ /**
1152
+ * Shared POST for every state-changing `/bff/*` call: same-origin, cookie
1153
+ * included, `X-BFF-Csrf` header attached. Throws a labelled error on non-2xx.
1154
+ */
1155
+ async postState(path, body, label) {
1156
+ const headers = {
1157
+ "Content-Type": JSON_CONTENT_TYPE,
1158
+ Accept: JSON_CONTENT_TYPE,
1159
+ [CSRF_HEADER]: CSRF_HEADER_VALUE
1160
+ };
1161
+ const response = await this.http({
1162
+ url: `${this.baseUrl}${path}`,
1163
+ method: "POST",
1164
+ headers,
1165
+ body: body === void 0 ? void 0 : JSON.stringify(body),
1166
+ credentials: "include"
1167
+ });
1168
+ if (!response.ok) {
1169
+ throw new Error(`${label} failed with status ${String(response.status)}`);
1170
+ }
1171
+ return response.data;
1172
+ }
1173
+ };
1174
+
1060
1175
  // src/utils/normalizeKeycloakUser.ts
1061
1176
  function isNonEmptyString(value) {
1062
1177
  return typeof value === "string" && value !== "";
@@ -1167,6 +1282,6 @@ function decodeUtf8(binary) {
1167
1282
  return new TextDecoder("utf-8").decode(bytes);
1168
1283
  }
1169
1284
 
1170
- export { AuthApiClient, AuthClient, AuthEventEmitter, BiometricGate, BrowserStorageTokenStorage, CookieTokenStorage, InMemoryTokenStorage, InactivityTracker, KeycloakRoles, RefreshInterceptor, SecureStoreTokenStorage, buildAuthorizationCodeBody, buildAuthorizationEndpoint, buildAuthorizationUrl, buildIssuerUrl, buildLogoutEndpoint, buildRefreshTokenBody, buildTokenEndpoint, buildUserInfoEndpoint, clearDiscoveryCache, computeExpiresAt, createFetchHttpClient, decodeJwt, deriveCodeChallenge, exchangeAuthorizationCode, extractAuthCode, fetchDiscoveryDocument, generateCodeVerifier, generatePkcePair, isKeycloakRole, isTokenExpired, normalizeKeycloakUser, normalizeTokenResponse, parseBaseUrlFromIssuer, parseRealmFromIssuer, refreshAccessToken, tokenResponseToAuthTokens };
1285
+ export { AuthApiClient, AuthClient, AuthEventEmitter, BffAuthClient, BiometricGate, BrowserStorageTokenStorage, CookieTokenStorage, InMemoryTokenStorage, InactivityTracker, KeycloakRoles, RefreshInterceptor, SecureStoreTokenStorage, buildAuthorizationCodeBody, buildAuthorizationEndpoint, buildAuthorizationUrl, buildIssuerUrl, buildLogoutEndpoint, buildRefreshTokenBody, buildTokenEndpoint, buildUserInfoEndpoint, clearDiscoveryCache, computeExpiresAt, createFetchHttpClient, decodeJwt, deriveCodeChallenge, exchangeAuthorizationCode, extractAuthCode, fetchDiscoveryDocument, generateCodeVerifier, generatePkcePair, isKeycloakRole, isTokenExpired, normalizeKeycloakUser, normalizeTokenResponse, parseBaseUrlFromIssuer, parseRealmFromIssuer, refreshAccessToken, tokenResponseToAuthTokens };
1171
1286
  //# sourceMappingURL=index.mjs.map
1172
1287
  //# sourceMappingURL=index.mjs.map