@authyon/auth 0.1.3 → 0.1.4

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.cjs CHANGED
@@ -113,7 +113,7 @@ var AuthyonClient = class {
113
113
  loginFinish: (assertion) => this.request("/auth/webauthn/login/finish", {
114
114
  method: "POST",
115
115
  body: assertion
116
- }).then((data) => this.setSession(data, "signed_in"))
116
+ }).then((data) => this.setSession({ tokens: data.tokens }, "signed_in")).then((session) => this.hydrateUser(session))
117
117
  };
118
118
  // ── Social sign-in (SSO) ─────────────────────────────────────────────────
119
119
  this.sso = {
@@ -134,9 +134,7 @@ var AuthyonClient = class {
134
134
  * POST /auth/sso/exchange — swaps the one-time code from the provider
135
135
  * callback for tokens and stores the session.
136
136
  */
137
- exchange: (code) => this.request("/auth/sso/exchange", { method: "POST", body: { code } }).then(
138
- (data) => this.setSession(data, "signed_in")
139
- )
137
+ exchange: (code) => this.request("/auth/sso/exchange", { method: "POST", body: { code } }).then((data) => this.setSession({ tokens: data.tokens }, "signed_in")).then((session) => this.hydrateUser(session))
140
138
  };
141
139
  // ── User ─────────────────────────────────────────────────────────────────
142
140
  this.user = {
@@ -144,7 +142,7 @@ var AuthyonClient = class {
144
142
  me: () => this.request("/auth/me", { bearer: true }).then(normalizeUser),
145
143
  /** GET /auth/sessions — active refresh-token sessions with device/IP data. */
146
144
  sessions: () => this.request("/auth/sessions", { bearer: true }),
147
- /** GET /auth/me/activities — recent account activity for the current user. */
145
+ /** GET /auth/me/activities — paginated recent account activity for the current user. */
148
146
  activities: (params = {}) => this.request(`/auth/me/activities?${toQuery(params)}`, { bearer: true }),
149
147
  /**
150
148
  * Revokes a single session by id (e.g. one entry from `sessions()`),
@@ -194,7 +192,7 @@ var AuthyonClient = class {
194
192
  method: "POST",
195
193
  bearer: true,
196
194
  body: { tenantSlug: organizationSlug }
197
- }).then((data) => this.setSession(data, "refreshed")),
195
+ }).then((data) => this.setSession({ tokens: data.tokens }, "refreshed")).then((session) => this.hydrateUser(session)),
198
196
  /** The organization the current session is scoped to, from the cached session — no network call. */
199
197
  current: () => this.getSession()?.user?.activeOrganization ?? null,
200
198
  members: {
@@ -332,9 +330,9 @@ var AuthyonClient = class {
332
330
  }
333
331
  setSession(raw, event) {
334
332
  const session = {
335
- ...raw,
333
+ ...raw.tokens,
336
334
  user: raw.user ? normalizeUser(raw.user) : void 0,
337
- expiresAt: Date.now() + raw.expiresIn * 1e3
335
+ expiresAt: Date.now() + raw.tokens.expiresIn * 1e3
338
336
  };
339
337
  this.storage.set(session);
340
338
  this.emit(event === "signed_out" ? { type: "signed_out" } : { type: event, session });
@@ -344,6 +342,23 @@ var AuthyonClient = class {
344
342
  this.storage.clear();
345
343
  this.emit({ type: "signed_out" });
346
344
  }
345
+ /**
346
+ * `/auth/login` and the other endpoints that mint a session don't return
347
+ * a `user` object on the wire — only `tokens` (plus `twoFactor`, when a
348
+ * challenge is required). Fetch the profile right after so callers get a
349
+ * fully-populated `session.user` without an extra manual round trip.
350
+ * Best-effort: keeps the session usable even if this fetch fails.
351
+ */
352
+ async hydrateUser(session) {
353
+ try {
354
+ const user = await this.user.me();
355
+ const hydrated = { ...session, user };
356
+ this.storage.set(hydrated);
357
+ return hydrated;
358
+ } catch {
359
+ return session;
360
+ }
361
+ }
347
362
  // ── HTTP core ────────────────────────────────────────────────────────────
348
363
  async request(path, options = {}, isRetry = false) {
349
364
  const headers = {
@@ -395,20 +410,20 @@ var AuthyonClient = class {
395
410
  async login(params) {
396
411
  const { organizationSlug, ...rest } = params;
397
412
  const body = organizationSlug ? { ...rest, tenantSlug: organizationSlug } : rest;
398
- const data = await this.request("/auth/login", {
399
- method: "POST",
400
- body
401
- });
402
- if (data.twoFactorRequired) {
403
- return data;
413
+ const data = await this.request("/auth/login", { method: "POST", body });
414
+ if (data.twoFactor) {
415
+ return { twoFactorRequired: true, ...data.twoFactor };
404
416
  }
405
- const session = this.setSession(data, "signed_in");
417
+ const session = await this.hydrateUser(this.setSession({ tokens: data.tokens }, "signed_in"));
406
418
  return { twoFactorRequired: false, session };
407
419
  }
408
420
  /** POST /auth/2fa/verify — redeems a 2FA challenge from `login()` and stores the session. */
409
421
  async verifyTwoFactor(params) {
410
- const data = await this.request("/auth/2fa/verify", { method: "POST", body: params });
411
- return this.setSession(data, "signed_in");
422
+ const data = await this.request("/auth/2fa/verify", {
423
+ method: "POST",
424
+ body: params
425
+ });
426
+ return this.hydrateUser(this.setSession({ tokens: data.tokens }, "signed_in"));
412
427
  }
413
428
  /** POST /auth/refresh — rotates the single-use refresh token (single-flight). */
414
429
  async refresh() {
@@ -420,7 +435,10 @@ var AuthyonClient = class {
420
435
  method: "POST",
421
436
  body: { refreshToken: current.refreshToken }
422
437
  }).then(
423
- (data) => this.setSession({ user: current.user, ...data }, "refreshed")
438
+ (data) => this.setSession(
439
+ { tokens: data.tokens, user: current.user },
440
+ "refreshed"
441
+ )
424
442
  ).catch((error) => {
425
443
  if (error instanceof AuthyonError && (error.status === 401 || error.status === 403)) {
426
444
  this.clearSession();
@@ -472,11 +490,11 @@ var AuthyonClient = class {
472
490
  }
473
491
  };
474
492
  function normalizeUser(raw) {
475
- const { tenants, activeTenant, ...rest } = raw;
493
+ const { tenant, tenants, activeTenant, ...rest } = raw;
476
494
  return {
477
495
  ...rest,
478
496
  organizations: raw.organizations ?? tenants,
479
- activeOrganization: raw.activeOrganization ?? activeTenant ?? null
497
+ activeOrganization: tenant ?? raw.activeOrganization ?? activeTenant ?? null
480
498
  };
481
499
  }
482
500
  function createClient(options) {
package/dist/index.d.cts CHANGED
@@ -35,9 +35,17 @@ interface User {
35
35
  id: string;
36
36
  email: string;
37
37
  username?: string;
38
+ emailConfirmed?: boolean;
39
+ firstName?: string | null;
40
+ lastName?: string | null;
41
+ roles?: string[];
42
+ permissions?: string[];
43
+ createdAt?: string;
44
+ lastLoginAt?: string;
38
45
  organizations?: Organization[];
39
46
  activeOrganization?: Organization | null;
40
- permissions?: string[];
47
+ /** Actions the user must complete before continuing (e.g. confirm e-mail). */
48
+ pendencies?: string[];
41
49
  }
42
50
  /** Token pair issued by login / refresh / tenant switch. */
43
51
  interface Session {
@@ -89,9 +97,18 @@ interface TwoFactorVerifyParams {
89
97
  /** Required when `method` is `"webauthn"`. */
90
98
  webAuthnAssertion?: WebAuthnAssertion;
91
99
  }
100
+ /** GET /auth/2fa/status — per-method enrolment flags, confirmed against the live API. */
92
101
  interface TwoFactorStatus {
93
- methods: TwoFactorMethod[];
94
- recoveryCodesRemaining?: number;
102
+ authenticatorEnabled: boolean;
103
+ authenticatorConfirmedAt?: string | null;
104
+ emailEnabled: boolean;
105
+ emailEnabledAt?: string | null;
106
+ /** Partially redacted (e.g. `"n**********@h***.com"`). */
107
+ emailHint?: string | null;
108
+ webAuthnEnabled: boolean;
109
+ webAuthnCredentialCount: number;
110
+ webAuthnCredentials: WebAuthnCredential[];
111
+ remainingRecoveryCodes: number;
95
112
  }
96
113
  interface AuthenticatorSetup {
97
114
  secret: string;
@@ -123,12 +140,27 @@ interface SsoProvider {
123
140
  /** URL to redirect the browser to in order to start this provider's flow. */
124
141
  startUrl: string;
125
142
  }
143
+ /** GET /auth/me/activities — one audit-trail entry, confirmed against the live API. */
126
144
  interface Activity {
127
145
  id: string;
128
- type: string;
129
- createdAt: string;
146
+ eventType: string;
147
+ occurredAt: string;
148
+ environmentId?: string;
130
149
  ip?: string;
131
- device?: string;
150
+ userAgent?: string;
151
+ /** JSON-encoded string — `JSON.parse` it for the event-specific payload. */
152
+ payloadJson?: string;
153
+ }
154
+ /** Paginated list envelope returned by `user.activities()`. */
155
+ interface Page<T> {
156
+ data: T[];
157
+ /** Item count actually returned for this page. */
158
+ perPage?: number;
159
+ pageSize: number;
160
+ total: number;
161
+ pages: number;
162
+ hasNext: boolean;
163
+ hasPrev: boolean;
132
164
  }
133
165
  /** A role available within an organization (tenant). */
134
166
  interface Role {
@@ -137,13 +169,17 @@ interface Role {
137
169
  description?: string;
138
170
  permissions?: string[];
139
171
  }
172
+ /** GET /auth/sessions — confirmed against the live API. */
140
173
  interface SessionInfo {
141
174
  id: string;
142
- createdAt?: string;
143
- lastUsedAt?: string;
144
- ip?: string;
145
- device?: string;
146
- current?: boolean;
175
+ createdAt: string;
176
+ expiresAt: string;
177
+ revokedAt?: string | null;
178
+ createdFromIp?: string;
179
+ isActive: boolean;
180
+ userAgent?: string;
181
+ lastUsedAt?: string | null;
182
+ lastUsedFromIp?: string | null;
147
183
  }
148
184
  interface IntrospectResult {
149
185
  active: boolean;
@@ -211,6 +247,14 @@ declare class AuthyonClient {
211
247
  private emit;
212
248
  private setSession;
213
249
  private clearSession;
250
+ /**
251
+ * `/auth/login` and the other endpoints that mint a session don't return
252
+ * a `user` object on the wire — only `tokens` (plus `twoFactor`, when a
253
+ * challenge is required). Fetch the profile right after so callers get a
254
+ * fully-populated `session.user` without an extra manual round trip.
255
+ * Best-effort: keeps the session usable even if this fetch fails.
256
+ */
257
+ private hydrateUser;
214
258
  private request;
215
259
  private toError;
216
260
  /** POST /auth/register — creates a new user (rate-limited to 20/hour per IP). */
@@ -266,8 +310,8 @@ declare class AuthyonClient {
266
310
  me: () => Promise<User>;
267
311
  /** GET /auth/sessions — active refresh-token sessions with device/IP data. */
268
312
  sessions: () => Promise<SessionInfo[]>;
269
- /** GET /auth/me/activities — recent account activity for the current user. */
270
- activities: (params?: PageParams) => Promise<Activity[]>;
313
+ /** GET /auth/me/activities — paginated recent account activity for the current user. */
314
+ activities: (params?: PageParams) => Promise<Page<Activity>>;
271
315
  /**
272
316
  * Revokes a single session by id (e.g. one entry from `sessions()`),
273
317
  * signing that device out without affecting the current one.
@@ -400,4 +444,4 @@ declare function memoryStorage(): TokenStorage;
400
444
  declare function localStorageAdapter(key?: string): TokenStorage;
401
445
  declare function defaultStorage(): TokenStorage;
402
446
 
403
- export { type Activity, type AuthEvent, type AuthStateListener, type AuthenticatorSetup, AuthyonClient, type AuthyonClientOptions, AuthyonError, type CreateOrganizationParams, ErrorCodes, type IntrospectResult, type InviteMemberParams, type LoginParams, type LoginResult, type Organization, type OrganizationMember, type PageParams, type RegisterParams, type Role, type Session, type SessionInfo, type SsoProvider, type TokenStorage, type TwoFactorChallenge, type TwoFactorMethod, type TwoFactorStatus, type TwoFactorVerifyParams, type User, type ValidateResult, type WebAuthnAssertion, type WebAuthnCeremonyStart, type WebAuthnCredential, createClient, defaultStorage, localStorageAdapter, memoryStorage };
447
+ export { type Activity, type AuthEvent, type AuthStateListener, type AuthenticatorSetup, AuthyonClient, type AuthyonClientOptions, AuthyonError, type CreateOrganizationParams, ErrorCodes, type IntrospectResult, type InviteMemberParams, type LoginParams, type LoginResult, type Organization, type OrganizationMember, type Page, type PageParams, type RegisterParams, type Role, type Session, type SessionInfo, type SsoProvider, type TokenStorage, type TwoFactorChallenge, type TwoFactorMethod, type TwoFactorStatus, type TwoFactorVerifyParams, type User, type ValidateResult, type WebAuthnAssertion, type WebAuthnCeremonyStart, type WebAuthnCredential, createClient, defaultStorage, localStorageAdapter, memoryStorage };
package/dist/index.d.ts CHANGED
@@ -35,9 +35,17 @@ interface User {
35
35
  id: string;
36
36
  email: string;
37
37
  username?: string;
38
+ emailConfirmed?: boolean;
39
+ firstName?: string | null;
40
+ lastName?: string | null;
41
+ roles?: string[];
42
+ permissions?: string[];
43
+ createdAt?: string;
44
+ lastLoginAt?: string;
38
45
  organizations?: Organization[];
39
46
  activeOrganization?: Organization | null;
40
- permissions?: string[];
47
+ /** Actions the user must complete before continuing (e.g. confirm e-mail). */
48
+ pendencies?: string[];
41
49
  }
42
50
  /** Token pair issued by login / refresh / tenant switch. */
43
51
  interface Session {
@@ -89,9 +97,18 @@ interface TwoFactorVerifyParams {
89
97
  /** Required when `method` is `"webauthn"`. */
90
98
  webAuthnAssertion?: WebAuthnAssertion;
91
99
  }
100
+ /** GET /auth/2fa/status — per-method enrolment flags, confirmed against the live API. */
92
101
  interface TwoFactorStatus {
93
- methods: TwoFactorMethod[];
94
- recoveryCodesRemaining?: number;
102
+ authenticatorEnabled: boolean;
103
+ authenticatorConfirmedAt?: string | null;
104
+ emailEnabled: boolean;
105
+ emailEnabledAt?: string | null;
106
+ /** Partially redacted (e.g. `"n**********@h***.com"`). */
107
+ emailHint?: string | null;
108
+ webAuthnEnabled: boolean;
109
+ webAuthnCredentialCount: number;
110
+ webAuthnCredentials: WebAuthnCredential[];
111
+ remainingRecoveryCodes: number;
95
112
  }
96
113
  interface AuthenticatorSetup {
97
114
  secret: string;
@@ -123,12 +140,27 @@ interface SsoProvider {
123
140
  /** URL to redirect the browser to in order to start this provider's flow. */
124
141
  startUrl: string;
125
142
  }
143
+ /** GET /auth/me/activities — one audit-trail entry, confirmed against the live API. */
126
144
  interface Activity {
127
145
  id: string;
128
- type: string;
129
- createdAt: string;
146
+ eventType: string;
147
+ occurredAt: string;
148
+ environmentId?: string;
130
149
  ip?: string;
131
- device?: string;
150
+ userAgent?: string;
151
+ /** JSON-encoded string — `JSON.parse` it for the event-specific payload. */
152
+ payloadJson?: string;
153
+ }
154
+ /** Paginated list envelope returned by `user.activities()`. */
155
+ interface Page<T> {
156
+ data: T[];
157
+ /** Item count actually returned for this page. */
158
+ perPage?: number;
159
+ pageSize: number;
160
+ total: number;
161
+ pages: number;
162
+ hasNext: boolean;
163
+ hasPrev: boolean;
132
164
  }
133
165
  /** A role available within an organization (tenant). */
134
166
  interface Role {
@@ -137,13 +169,17 @@ interface Role {
137
169
  description?: string;
138
170
  permissions?: string[];
139
171
  }
172
+ /** GET /auth/sessions — confirmed against the live API. */
140
173
  interface SessionInfo {
141
174
  id: string;
142
- createdAt?: string;
143
- lastUsedAt?: string;
144
- ip?: string;
145
- device?: string;
146
- current?: boolean;
175
+ createdAt: string;
176
+ expiresAt: string;
177
+ revokedAt?: string | null;
178
+ createdFromIp?: string;
179
+ isActive: boolean;
180
+ userAgent?: string;
181
+ lastUsedAt?: string | null;
182
+ lastUsedFromIp?: string | null;
147
183
  }
148
184
  interface IntrospectResult {
149
185
  active: boolean;
@@ -211,6 +247,14 @@ declare class AuthyonClient {
211
247
  private emit;
212
248
  private setSession;
213
249
  private clearSession;
250
+ /**
251
+ * `/auth/login` and the other endpoints that mint a session don't return
252
+ * a `user` object on the wire — only `tokens` (plus `twoFactor`, when a
253
+ * challenge is required). Fetch the profile right after so callers get a
254
+ * fully-populated `session.user` without an extra manual round trip.
255
+ * Best-effort: keeps the session usable even if this fetch fails.
256
+ */
257
+ private hydrateUser;
214
258
  private request;
215
259
  private toError;
216
260
  /** POST /auth/register — creates a new user (rate-limited to 20/hour per IP). */
@@ -266,8 +310,8 @@ declare class AuthyonClient {
266
310
  me: () => Promise<User>;
267
311
  /** GET /auth/sessions — active refresh-token sessions with device/IP data. */
268
312
  sessions: () => Promise<SessionInfo[]>;
269
- /** GET /auth/me/activities — recent account activity for the current user. */
270
- activities: (params?: PageParams) => Promise<Activity[]>;
313
+ /** GET /auth/me/activities — paginated recent account activity for the current user. */
314
+ activities: (params?: PageParams) => Promise<Page<Activity>>;
271
315
  /**
272
316
  * Revokes a single session by id (e.g. one entry from `sessions()`),
273
317
  * signing that device out without affecting the current one.
@@ -400,4 +444,4 @@ declare function memoryStorage(): TokenStorage;
400
444
  declare function localStorageAdapter(key?: string): TokenStorage;
401
445
  declare function defaultStorage(): TokenStorage;
402
446
 
403
- export { type Activity, type AuthEvent, type AuthStateListener, type AuthenticatorSetup, AuthyonClient, type AuthyonClientOptions, AuthyonError, type CreateOrganizationParams, ErrorCodes, type IntrospectResult, type InviteMemberParams, type LoginParams, type LoginResult, type Organization, type OrganizationMember, type PageParams, type RegisterParams, type Role, type Session, type SessionInfo, type SsoProvider, type TokenStorage, type TwoFactorChallenge, type TwoFactorMethod, type TwoFactorStatus, type TwoFactorVerifyParams, type User, type ValidateResult, type WebAuthnAssertion, type WebAuthnCeremonyStart, type WebAuthnCredential, createClient, defaultStorage, localStorageAdapter, memoryStorage };
447
+ export { type Activity, type AuthEvent, type AuthStateListener, type AuthenticatorSetup, AuthyonClient, type AuthyonClientOptions, AuthyonError, type CreateOrganizationParams, ErrorCodes, type IntrospectResult, type InviteMemberParams, type LoginParams, type LoginResult, type Organization, type OrganizationMember, type Page, type PageParams, type RegisterParams, type Role, type Session, type SessionInfo, type SsoProvider, type TokenStorage, type TwoFactorChallenge, type TwoFactorMethod, type TwoFactorStatus, type TwoFactorVerifyParams, type User, type ValidateResult, type WebAuthnAssertion, type WebAuthnCeremonyStart, type WebAuthnCredential, createClient, defaultStorage, localStorageAdapter, memoryStorage };
package/dist/index.js CHANGED
@@ -81,7 +81,7 @@ var AuthyonClient = class {
81
81
  loginFinish: (assertion) => this.request("/auth/webauthn/login/finish", {
82
82
  method: "POST",
83
83
  body: assertion
84
- }).then((data) => this.setSession(data, "signed_in"))
84
+ }).then((data) => this.setSession({ tokens: data.tokens }, "signed_in")).then((session) => this.hydrateUser(session))
85
85
  };
86
86
  // ── Social sign-in (SSO) ─────────────────────────────────────────────────
87
87
  this.sso = {
@@ -102,9 +102,7 @@ var AuthyonClient = class {
102
102
  * POST /auth/sso/exchange — swaps the one-time code from the provider
103
103
  * callback for tokens and stores the session.
104
104
  */
105
- exchange: (code) => this.request("/auth/sso/exchange", { method: "POST", body: { code } }).then(
106
- (data) => this.setSession(data, "signed_in")
107
- )
105
+ exchange: (code) => this.request("/auth/sso/exchange", { method: "POST", body: { code } }).then((data) => this.setSession({ tokens: data.tokens }, "signed_in")).then((session) => this.hydrateUser(session))
108
106
  };
109
107
  // ── User ─────────────────────────────────────────────────────────────────
110
108
  this.user = {
@@ -112,7 +110,7 @@ var AuthyonClient = class {
112
110
  me: () => this.request("/auth/me", { bearer: true }).then(normalizeUser),
113
111
  /** GET /auth/sessions — active refresh-token sessions with device/IP data. */
114
112
  sessions: () => this.request("/auth/sessions", { bearer: true }),
115
- /** GET /auth/me/activities — recent account activity for the current user. */
113
+ /** GET /auth/me/activities — paginated recent account activity for the current user. */
116
114
  activities: (params = {}) => this.request(`/auth/me/activities?${toQuery(params)}`, { bearer: true }),
117
115
  /**
118
116
  * Revokes a single session by id (e.g. one entry from `sessions()`),
@@ -162,7 +160,7 @@ var AuthyonClient = class {
162
160
  method: "POST",
163
161
  bearer: true,
164
162
  body: { tenantSlug: organizationSlug }
165
- }).then((data) => this.setSession(data, "refreshed")),
163
+ }).then((data) => this.setSession({ tokens: data.tokens }, "refreshed")).then((session) => this.hydrateUser(session)),
166
164
  /** The organization the current session is scoped to, from the cached session — no network call. */
167
165
  current: () => this.getSession()?.user?.activeOrganization ?? null,
168
166
  members: {
@@ -300,9 +298,9 @@ var AuthyonClient = class {
300
298
  }
301
299
  setSession(raw, event) {
302
300
  const session = {
303
- ...raw,
301
+ ...raw.tokens,
304
302
  user: raw.user ? normalizeUser(raw.user) : void 0,
305
- expiresAt: Date.now() + raw.expiresIn * 1e3
303
+ expiresAt: Date.now() + raw.tokens.expiresIn * 1e3
306
304
  };
307
305
  this.storage.set(session);
308
306
  this.emit(event === "signed_out" ? { type: "signed_out" } : { type: event, session });
@@ -312,6 +310,23 @@ var AuthyonClient = class {
312
310
  this.storage.clear();
313
311
  this.emit({ type: "signed_out" });
314
312
  }
313
+ /**
314
+ * `/auth/login` and the other endpoints that mint a session don't return
315
+ * a `user` object on the wire — only `tokens` (plus `twoFactor`, when a
316
+ * challenge is required). Fetch the profile right after so callers get a
317
+ * fully-populated `session.user` without an extra manual round trip.
318
+ * Best-effort: keeps the session usable even if this fetch fails.
319
+ */
320
+ async hydrateUser(session) {
321
+ try {
322
+ const user = await this.user.me();
323
+ const hydrated = { ...session, user };
324
+ this.storage.set(hydrated);
325
+ return hydrated;
326
+ } catch {
327
+ return session;
328
+ }
329
+ }
315
330
  // ── HTTP core ────────────────────────────────────────────────────────────
316
331
  async request(path, options = {}, isRetry = false) {
317
332
  const headers = {
@@ -363,20 +378,20 @@ var AuthyonClient = class {
363
378
  async login(params) {
364
379
  const { organizationSlug, ...rest } = params;
365
380
  const body = organizationSlug ? { ...rest, tenantSlug: organizationSlug } : rest;
366
- const data = await this.request("/auth/login", {
367
- method: "POST",
368
- body
369
- });
370
- if (data.twoFactorRequired) {
371
- return data;
381
+ const data = await this.request("/auth/login", { method: "POST", body });
382
+ if (data.twoFactor) {
383
+ return { twoFactorRequired: true, ...data.twoFactor };
372
384
  }
373
- const session = this.setSession(data, "signed_in");
385
+ const session = await this.hydrateUser(this.setSession({ tokens: data.tokens }, "signed_in"));
374
386
  return { twoFactorRequired: false, session };
375
387
  }
376
388
  /** POST /auth/2fa/verify — redeems a 2FA challenge from `login()` and stores the session. */
377
389
  async verifyTwoFactor(params) {
378
- const data = await this.request("/auth/2fa/verify", { method: "POST", body: params });
379
- return this.setSession(data, "signed_in");
390
+ const data = await this.request("/auth/2fa/verify", {
391
+ method: "POST",
392
+ body: params
393
+ });
394
+ return this.hydrateUser(this.setSession({ tokens: data.tokens }, "signed_in"));
380
395
  }
381
396
  /** POST /auth/refresh — rotates the single-use refresh token (single-flight). */
382
397
  async refresh() {
@@ -388,7 +403,10 @@ var AuthyonClient = class {
388
403
  method: "POST",
389
404
  body: { refreshToken: current.refreshToken }
390
405
  }).then(
391
- (data) => this.setSession({ user: current.user, ...data }, "refreshed")
406
+ (data) => this.setSession(
407
+ { tokens: data.tokens, user: current.user },
408
+ "refreshed"
409
+ )
392
410
  ).catch((error) => {
393
411
  if (error instanceof AuthyonError && (error.status === 401 || error.status === 403)) {
394
412
  this.clearSession();
@@ -440,11 +458,11 @@ var AuthyonClient = class {
440
458
  }
441
459
  };
442
460
  function normalizeUser(raw) {
443
- const { tenants, activeTenant, ...rest } = raw;
461
+ const { tenant, tenants, activeTenant, ...rest } = raw;
444
462
  return {
445
463
  ...rest,
446
464
  organizations: raw.organizations ?? tenants,
447
- activeOrganization: raw.activeOrganization ?? activeTenant ?? null
465
+ activeOrganization: tenant ?? raw.activeOrganization ?? activeTenant ?? null
448
466
  };
449
467
  }
450
468
  function createClient(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authyon/auth",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Authyon SDK for browsers — auth, sessions, multi-tenant and 2FA for vanilla JS/TS.",
5
5
  "license": "MIT",
6
6
  "type": "module",