@nuria-tech/auth-sdk 1.0.3 → 1.0.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.d.cts CHANGED
@@ -1,74 +1,6 @@
1
- interface TokenSet {
2
- accessToken: string;
3
- tokenType?: string;
4
- expiresIn?: number;
5
- refreshToken?: string;
6
- idToken?: string;
7
- scope?: string;
8
- expiresAt?: number;
9
- }
10
- interface Session {
11
- tokens: TokenSet;
12
- createdAt: number;
13
- }
14
- interface StartLoginOptions {
15
- loginHint?: string;
16
- scopes?: string[];
17
- extraParams?: Record<string, string>;
18
- }
19
- interface StorageAdapter {
20
- get(key: string): Promise<string | null> | string | null;
21
- set(key: string, value: string): Promise<void> | void;
22
- remove(key: string): Promise<void> | void;
23
- }
24
- interface AuthTransportRequest {
25
- method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
26
- headers?: Record<string, string>;
27
- credentials?: RequestCredentials;
28
- query?: Record<string, string | undefined>;
29
- body?: unknown;
30
- timeoutMs?: number;
31
- retries?: number;
32
- }
33
- interface AuthTransportResponse<T = unknown> {
34
- status: number;
35
- data: T;
36
- headers: Headers;
37
- }
38
- interface AuthTransport {
39
- request<T = unknown>(url: string, req?: AuthTransportRequest): Promise<AuthTransportResponse<T>>;
40
- }
41
- interface TransportInterceptor {
42
- onRequest?: (url: string, req: AuthTransportRequest) => Promise<AuthTransportRequest> | AuthTransportRequest;
43
- onResponse?: <T>(res: AuthTransportResponse<T>) => Promise<AuthTransportResponse<T>> | AuthTransportResponse<T>;
44
- }
45
- interface AuthConfig {
46
- clientId: string;
47
- baseUrl?: string;
48
- authorizationEndpoint?: string;
49
- tokenEndpoint?: string;
50
- redirectUri: string;
51
- scope?: string;
52
- logoutEndpoint?: string;
53
- userinfoEndpoint?: string;
54
- storage?: StorageAdapter;
55
- transport?: AuthTransport;
56
- onRedirect?: (url: string) => void | Promise<void>;
57
- enableRefreshToken?: boolean;
58
- now?: () => number;
59
- }
60
- interface AuthClient {
61
- startLogin(options?: StartLoginOptions): Promise<void>;
62
- handleRedirectCallback(callbackUrl?: string): Promise<Session>;
63
- getSession(): Session | null;
64
- getAccessToken(): Promise<string | null>;
65
- logout(options?: {
66
- returnTo?: string;
67
- }): Promise<void>;
68
- isAuthenticated(): boolean;
69
- onAuthStateChanged(handler: (session: Session | null) => void): () => void;
70
- getUserinfo(): Promise<Record<string, unknown>>;
71
- }
1
+ import { A as AuthConfig, a as AuthClient, S as StorageAdapter, b as AuthTransport, T as TransportInterceptor, c as AuthTransportRequest, d as AuthTransportResponse } from './types-2k4ZYpF4.cjs';
2
+ export { G as GoogleLoginOptions, L as LoginCodeChallengeOptions, P as PasswordLoginOptions, e as Session, f as StartLoginOptions, g as TokenSet, h as TwoFactorChallenge, V as VerifyLoginCodeOptions } from './types-2k4ZYpF4.cjs';
3
+ export { C as CookieStorageAdapter } from './cookie-storage-adapter-FKYkZ--Y.cjs';
72
4
 
73
5
  declare function createAuthClient(config: AuthConfig): AuthClient;
74
6
 
@@ -87,19 +19,6 @@ declare class WebStorageAdapter implements StorageAdapter {
87
19
  remove(key: string): void;
88
20
  }
89
21
 
90
- interface CookieStorageCallbacks {
91
- getCookie(name: string): string | null | Promise<string | null>;
92
- setCookie(name: string, value: string): void | Promise<void>;
93
- removeCookie(name: string): void | Promise<void>;
94
- }
95
- declare class CookieStorageAdapter implements StorageAdapter {
96
- private readonly callbacks;
97
- constructor(callbacks: CookieStorageCallbacks);
98
- get(key: string): Promise<string | null>;
99
- set(key: string, value: string): Promise<void>;
100
- remove(key: string): Promise<void>;
101
- }
102
-
103
22
  interface BrowserCookieStorageOptions {
104
23
  domain?: string;
105
24
  path?: string;
@@ -143,4 +62,4 @@ declare class AuthError extends Error {
143
62
  constructor(code: AuthErrorCode, message: string, cause?: unknown | undefined);
144
63
  }
145
64
 
146
- export { type AuthClient, type AuthConfig, AuthError, AuthErrorCode, type AuthTransport, type AuthTransportRequest, type AuthTransportResponse, type BrowserCookieStorageOptions, CookieStorageAdapter, FetchAuthTransport, MemoryStorageAdapter, type Session, type StartLoginOptions, type StorageAdapter, type TokenSet, type TransportInterceptor, WebStorageAdapter, createAuthClient, createBrowserCookieStorage };
65
+ export { AuthClient, AuthConfig, AuthError, AuthErrorCode, AuthTransport, AuthTransportRequest, AuthTransportResponse, type BrowserCookieStorageOptions, FetchAuthTransport, MemoryStorageAdapter, StorageAdapter, TransportInterceptor, WebStorageAdapter, createAuthClient, createBrowserCookieStorage };
package/dist/index.d.ts CHANGED
@@ -1,74 +1,6 @@
1
- interface TokenSet {
2
- accessToken: string;
3
- tokenType?: string;
4
- expiresIn?: number;
5
- refreshToken?: string;
6
- idToken?: string;
7
- scope?: string;
8
- expiresAt?: number;
9
- }
10
- interface Session {
11
- tokens: TokenSet;
12
- createdAt: number;
13
- }
14
- interface StartLoginOptions {
15
- loginHint?: string;
16
- scopes?: string[];
17
- extraParams?: Record<string, string>;
18
- }
19
- interface StorageAdapter {
20
- get(key: string): Promise<string | null> | string | null;
21
- set(key: string, value: string): Promise<void> | void;
22
- remove(key: string): Promise<void> | void;
23
- }
24
- interface AuthTransportRequest {
25
- method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
26
- headers?: Record<string, string>;
27
- credentials?: RequestCredentials;
28
- query?: Record<string, string | undefined>;
29
- body?: unknown;
30
- timeoutMs?: number;
31
- retries?: number;
32
- }
33
- interface AuthTransportResponse<T = unknown> {
34
- status: number;
35
- data: T;
36
- headers: Headers;
37
- }
38
- interface AuthTransport {
39
- request<T = unknown>(url: string, req?: AuthTransportRequest): Promise<AuthTransportResponse<T>>;
40
- }
41
- interface TransportInterceptor {
42
- onRequest?: (url: string, req: AuthTransportRequest) => Promise<AuthTransportRequest> | AuthTransportRequest;
43
- onResponse?: <T>(res: AuthTransportResponse<T>) => Promise<AuthTransportResponse<T>> | AuthTransportResponse<T>;
44
- }
45
- interface AuthConfig {
46
- clientId: string;
47
- baseUrl?: string;
48
- authorizationEndpoint?: string;
49
- tokenEndpoint?: string;
50
- redirectUri: string;
51
- scope?: string;
52
- logoutEndpoint?: string;
53
- userinfoEndpoint?: string;
54
- storage?: StorageAdapter;
55
- transport?: AuthTransport;
56
- onRedirect?: (url: string) => void | Promise<void>;
57
- enableRefreshToken?: boolean;
58
- now?: () => number;
59
- }
60
- interface AuthClient {
61
- startLogin(options?: StartLoginOptions): Promise<void>;
62
- handleRedirectCallback(callbackUrl?: string): Promise<Session>;
63
- getSession(): Session | null;
64
- getAccessToken(): Promise<string | null>;
65
- logout(options?: {
66
- returnTo?: string;
67
- }): Promise<void>;
68
- isAuthenticated(): boolean;
69
- onAuthStateChanged(handler: (session: Session | null) => void): () => void;
70
- getUserinfo(): Promise<Record<string, unknown>>;
71
- }
1
+ import { A as AuthConfig, a as AuthClient, S as StorageAdapter, b as AuthTransport, T as TransportInterceptor, c as AuthTransportRequest, d as AuthTransportResponse } from './types-2k4ZYpF4.js';
2
+ export { G as GoogleLoginOptions, L as LoginCodeChallengeOptions, P as PasswordLoginOptions, e as Session, f as StartLoginOptions, g as TokenSet, h as TwoFactorChallenge, V as VerifyLoginCodeOptions } from './types-2k4ZYpF4.js';
3
+ export { C as CookieStorageAdapter } from './cookie-storage-adapter-EJeGX8Tl.js';
72
4
 
73
5
  declare function createAuthClient(config: AuthConfig): AuthClient;
74
6
 
@@ -87,19 +19,6 @@ declare class WebStorageAdapter implements StorageAdapter {
87
19
  remove(key: string): void;
88
20
  }
89
21
 
90
- interface CookieStorageCallbacks {
91
- getCookie(name: string): string | null | Promise<string | null>;
92
- setCookie(name: string, value: string): void | Promise<void>;
93
- removeCookie(name: string): void | Promise<void>;
94
- }
95
- declare class CookieStorageAdapter implements StorageAdapter {
96
- private readonly callbacks;
97
- constructor(callbacks: CookieStorageCallbacks);
98
- get(key: string): Promise<string | null>;
99
- set(key: string, value: string): Promise<void>;
100
- remove(key: string): Promise<void>;
101
- }
102
-
103
22
  interface BrowserCookieStorageOptions {
104
23
  domain?: string;
105
24
  path?: string;
@@ -143,4 +62,4 @@ declare class AuthError extends Error {
143
62
  constructor(code: AuthErrorCode, message: string, cause?: unknown | undefined);
144
63
  }
145
64
 
146
- export { type AuthClient, type AuthConfig, AuthError, AuthErrorCode, type AuthTransport, type AuthTransportRequest, type AuthTransportResponse, type BrowserCookieStorageOptions, CookieStorageAdapter, FetchAuthTransport, MemoryStorageAdapter, type Session, type StartLoginOptions, type StorageAdapter, type TokenSet, type TransportInterceptor, WebStorageAdapter, createAuthClient, createBrowserCookieStorage };
65
+ export { AuthClient, AuthConfig, AuthError, AuthErrorCode, AuthTransport, AuthTransportRequest, AuthTransportResponse, type BrowserCookieStorageOptions, FetchAuthTransport, MemoryStorageAdapter, StorageAdapter, TransportInterceptor, WebStorageAdapter, createAuthClient, createBrowserCookieStorage };
package/dist/index.js CHANGED
@@ -68,23 +68,25 @@ var STORAGE_KEYS = {
68
68
  codeVerifier: "nuria:oauth:code_verifier"
69
69
  };
70
70
  function normalizeTokenSet(raw, now) {
71
- var _a, _b, _c, _d, _e, _f;
72
- const accessToken = (_a = raw.access_token) != null ? _a : raw.accessToken;
71
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
72
+ const accessToken = (_b = (_a = raw.access_token) != null ? _a : raw.accessToken) != null ? _b : raw.Token;
73
73
  if (!accessToken || typeof accessToken !== "string") {
74
74
  throw new AuthError(
75
75
  "TOKEN_EXCHANGE_FAILED" /* TOKEN_EXCHANGE_FAILED */,
76
76
  "Missing access token in token response"
77
77
  );
78
78
  }
79
- const expiresIn = Number((_c = (_b = raw.expires_in) != null ? _b : raw.expiresIn) != null ? _c : 0) || void 0;
79
+ const expiresIn = Number((_d = (_c = raw.expires_in) != null ? _c : raw.expiresIn) != null ? _d : 0) || void 0;
80
+ const expiresAtFromResponse = Number((_e = raw.ExpiresAt) != null ? _e : 0) || void 0;
81
+ const computedExpiresAt = expiresIn != null ? now() + expiresIn * 1e3 : expiresAtFromResponse ? expiresAtFromResponse : void 0;
80
82
  return {
81
83
  accessToken,
82
- tokenType: (_d = raw.token_type) != null ? _d : raw.tokenType,
84
+ tokenType: (_g = (_f = raw.token_type) != null ? _f : raw.tokenType) != null ? _g : raw.TokenType,
83
85
  expiresIn,
84
- refreshToken: (_e = raw.refresh_token) != null ? _e : raw.refreshToken,
85
- idToken: (_f = raw.id_token) != null ? _f : raw.idToken,
86
+ refreshToken: (_i = (_h = raw.refresh_token) != null ? _h : raw.refreshToken) != null ? _i : raw.RefreshToken,
87
+ idToken: (_j = raw.id_token) != null ? _j : raw.idToken,
86
88
  scope: raw.scope,
87
- expiresAt: expiresIn ? now() + expiresIn * 1e3 : void 0
89
+ expiresAt: computedExpiresAt
88
90
  };
89
91
  }
90
92
  async function safeGet(storage, key) {
@@ -335,7 +337,6 @@ var DefaultAuthClient = class {
335
337
  "State validation failed"
336
338
  );
337
339
  }
338
- await safeRemove(this.storage, STORAGE_KEYS.state);
339
340
  return this.exchangeCode(code);
340
341
  }
341
342
  getSession() {
@@ -360,11 +361,27 @@ var DefaultAuthClient = class {
360
361
  }
361
362
  async logout(options) {
362
363
  if (options == null ? void 0 : options.returnTo) {
363
- const returnTo = options.returnTo;
364
- if (returnTo.startsWith("//") || !/^https?:\/\//.test(returnTo)) {
364
+ let returnToUrl;
365
+ try {
366
+ returnToUrl = new URL(options.returnTo);
367
+ } catch (e) {
368
+ throw new AuthError(
369
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
370
+ "returnTo must be a valid absolute URL"
371
+ );
372
+ }
373
+ const isHttps = returnToUrl.protocol === "https:";
374
+ const isLocalHttp = returnToUrl.protocol === "http:" && (returnToUrl.hostname === "localhost" || returnToUrl.hostname === "127.0.0.1" || returnToUrl.hostname === "[::1]");
375
+ if (!isHttps && !isLocalHttp) {
376
+ throw new AuthError(
377
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
378
+ "returnTo must use https:// (or http:// only for localhost)"
379
+ );
380
+ }
381
+ if (returnToUrl.username || returnToUrl.password) {
365
382
  throw new AuthError(
366
383
  "INVALID_CONFIG" /* INVALID_CONFIG */,
367
- "returnTo must be an absolute https:// or http:// URL"
384
+ "returnTo must not include URL credentials"
368
385
  );
369
386
  }
370
387
  }
@@ -387,8 +404,12 @@ var DefaultAuthClient = class {
387
404
  }
388
405
  }
389
406
  isAuthenticated() {
390
- var _a;
391
- return Boolean((_a = this.session) == null ? void 0 : _a.tokens.accessToken);
407
+ var _a, _b;
408
+ const accessToken = (_a = this.session) == null ? void 0 : _a.tokens.accessToken;
409
+ if (!accessToken) return false;
410
+ const exp = (_b = this.session) == null ? void 0 : _b.tokens.expiresAt;
411
+ if (exp && exp <= this.now()) return false;
412
+ return true;
392
413
  }
393
414
  onAuthStateChanged(handler) {
394
415
  this.listeners.add(handler);
@@ -414,6 +435,103 @@ var DefaultAuthClient = class {
414
435
  );
415
436
  return response.data;
416
437
  }
438
+ async startLoginCodeChallenge(options) {
439
+ var _a, _b, _c, _d, _e, _f, _g;
440
+ if (!(options == null ? void 0 : options.email)) {
441
+ throw new AuthError(
442
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
443
+ "email is required for startLoginCodeChallenge"
444
+ );
445
+ }
446
+ const response = await this.transport.request(
447
+ `${this.config.baseUrl}/v2/login-code/challenge`,
448
+ {
449
+ method: "POST",
450
+ credentials: "include",
451
+ body: {
452
+ email: options.email,
453
+ channel: (_a = options.channel) != null ? _a : "email",
454
+ destination: options.destination,
455
+ purpose: (_b = options.purpose) != null ? _b : "login"
456
+ }
457
+ }
458
+ );
459
+ return {
460
+ challengeId: String((_c = response.data.challengeId) != null ? _c : ""),
461
+ channel: String((_d = response.data.channel) != null ? _d : ""),
462
+ destinationMasked: String((_e = response.data.destinationMasked) != null ? _e : ""),
463
+ expiresAt: Number((_f = response.data.expiresAt) != null ? _f : 0),
464
+ purpose: String((_g = response.data.purpose) != null ? _g : "login")
465
+ };
466
+ }
467
+ async verifyLoginCode(options) {
468
+ if (!(options == null ? void 0 : options.challengeId) || !(options == null ? void 0 : options.code)) {
469
+ throw new AuthError(
470
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
471
+ "challengeId and code are required for verifyLoginCode"
472
+ );
473
+ }
474
+ const response = await this.transport.request(
475
+ `${this.config.baseUrl}/v2/2fa/verify-login`,
476
+ {
477
+ method: "POST",
478
+ credentials: "include",
479
+ body: {
480
+ challengeId: options.challengeId,
481
+ code: options.code
482
+ }
483
+ }
484
+ );
485
+ const tokens = normalizeTokenSet(response.data, this.now);
486
+ return this.createSession(tokens);
487
+ }
488
+ async loginWithCodeSent(options) {
489
+ return this.startLoginCodeChallenge(options);
490
+ }
491
+ async completeLoginWithCode(options) {
492
+ return this.verifyLoginCode(options);
493
+ }
494
+ async loginWithGoogle(options) {
495
+ if (!(options == null ? void 0 : options.idToken)) {
496
+ throw new AuthError(
497
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
498
+ "idToken is required for loginWithGoogle"
499
+ );
500
+ }
501
+ const response = await this.transport.request(
502
+ `${this.config.baseUrl}/v2/google`,
503
+ {
504
+ method: "POST",
505
+ credentials: "include",
506
+ body: {
507
+ idToken: options.idToken
508
+ }
509
+ }
510
+ );
511
+ const tokens = normalizeTokenSet(response.data, this.now);
512
+ return this.createSession(tokens);
513
+ }
514
+ async loginWithPassword(options) {
515
+ if (!(options == null ? void 0 : options.email) || !(options == null ? void 0 : options.password)) {
516
+ throw new AuthError(
517
+ "INVALID_CONFIG" /* INVALID_CONFIG */,
518
+ "email and password are required for loginWithPassword"
519
+ );
520
+ }
521
+ const response = await this.transport.request(
522
+ `${this.config.baseUrl}/v2/login`,
523
+ {
524
+ method: "POST",
525
+ credentials: "include",
526
+ body: {
527
+ email: options.email,
528
+ password: options.password
529
+ }
530
+ }
531
+ );
532
+ const tokens = normalizeTokenSet(response.data, this.now);
533
+ return this.createSession(tokens);
534
+ }
417
535
  async exchangeCode(code) {
418
536
  const verifier = await safeGet(this.storage, STORAGE_KEYS.codeVerifier);
419
537
  if (!verifier) {
@@ -438,6 +556,7 @@ var DefaultAuthClient = class {
438
556
  }
439
557
  );
440
558
  const tokens = normalizeTokenSet(response.data, this.now);
559
+ await safeRemove(this.storage, STORAGE_KEYS.state);
441
560
  await safeRemove(this.storage, STORAGE_KEYS.codeVerifier);
442
561
  return this.createSession(tokens);
443
562
  }
@@ -607,8 +726,18 @@ var CookieStorageAdapter = class {
607
726
  var getCookieValue = (name) => {
608
727
  var _a;
609
728
  if (typeof document === "undefined") return null;
610
- const result = document.cookie.match(`(^|;)\\s*${name}\\s*=\\s*([^;]+)`);
611
- return result ? (_a = result.pop()) != null ? _a : null : null;
729
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
730
+ const result = document.cookie.match(
731
+ `(^|;)\\s*${escapedName}\\s*=\\s*([^;]+)`
732
+ );
733
+ if (!result) return null;
734
+ const raw = (_a = result.pop()) != null ? _a : null;
735
+ if (raw == null) return null;
736
+ try {
737
+ return decodeURIComponent(raw);
738
+ } catch (e) {
739
+ return raw;
740
+ }
612
741
  };
613
742
  function createBrowserCookieStorage(options = {}) {
614
743
  const { domain, path = "/", sameSite = "strict", secure = true } = options;
@@ -617,7 +746,7 @@ function createBrowserCookieStorage(options = {}) {
617
746
  };
618
747
  const set = (key, value) => {
619
748
  if (typeof document === "undefined") return;
620
- let cookie = `${key}=${value}`;
749
+ let cookie = `${key}=${encodeURIComponent(value)}`;
621
750
  if (path) cookie += `; path=${path}`;
622
751
  if (domain) cookie += `; domain=${domain}`;
623
752
  if (sameSite) cookie += `; samesite=${sameSite}`;