@owox/idp-owox-better-auth 0.18.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.
Files changed (156) hide show
  1. package/README.md +119 -0
  2. package/dist/client/IdentityOwoxClient.d.ts +41 -0
  3. package/dist/client/IdentityOwoxClient.d.ts.map +1 -0
  4. package/dist/client/IdentityOwoxClient.js +128 -0
  5. package/dist/client/dto/authFlowDto.d.ts +27 -0
  6. package/dist/client/dto/authFlowDto.d.ts.map +1 -0
  7. package/dist/client/dto/authFlowDto.js +5 -0
  8. package/dist/client/dto/idpOwoxPayloadDto.d.ts +29 -0
  9. package/dist/client/dto/idpOwoxPayloadDto.d.ts.map +1 -0
  10. package/dist/client/dto/idpOwoxPayloadDto.js +28 -0
  11. package/dist/client/dto/index.d.ts +11 -0
  12. package/dist/client/dto/index.d.ts.map +1 -0
  13. package/dist/client/dto/index.js +10 -0
  14. package/dist/client/dto/introspectionDto.d.ts +70 -0
  15. package/dist/client/dto/introspectionDto.d.ts.map +1 -0
  16. package/dist/client/dto/introspectionDto.js +15 -0
  17. package/dist/client/dto/jwksDto.d.ts +102 -0
  18. package/dist/client/dto/jwksDto.d.ts.map +1 -0
  19. package/dist/client/dto/jwksDto.js +18 -0
  20. package/dist/client/dto/revocationDto.d.ts +11 -0
  21. package/dist/client/dto/revocationDto.d.ts.map +1 -0
  22. package/dist/client/dto/revocationDto.js +1 -0
  23. package/dist/client/dto/tokenDto.d.ts +33 -0
  24. package/dist/client/dto/tokenDto.d.ts.map +1 -0
  25. package/dist/client/dto/tokenDto.js +9 -0
  26. package/dist/client/dto/tokenType.d.ts +5 -0
  27. package/dist/client/dto/tokenType.d.ts.map +1 -0
  28. package/dist/client/dto/tokenType.js +1 -0
  29. package/dist/client/index.d.ts +6 -0
  30. package/dist/client/index.d.ts.map +1 -0
  31. package/dist/client/index.js +5 -0
  32. package/dist/config/idp-better-auth-config.d.ts +9 -0
  33. package/dist/config/idp-better-auth-config.d.ts.map +1 -0
  34. package/dist/config/idp-better-auth-config.js +101 -0
  35. package/dist/config/idp-owox-config.d.ts +195 -0
  36. package/dist/config/idp-owox-config.d.ts.map +1 -0
  37. package/dist/config/idp-owox-config.js +252 -0
  38. package/dist/config/index.d.ts +6 -0
  39. package/dist/config/index.d.ts.map +1 -0
  40. package/dist/config/index.js +5 -0
  41. package/dist/core/constants.d.ts +14 -0
  42. package/dist/core/constants.d.ts.map +1 -0
  43. package/dist/core/constants.js +13 -0
  44. package/dist/core/exceptions.d.ts +27 -0
  45. package/dist/core/exceptions.d.ts.map +1 -0
  46. package/dist/core/exceptions.js +36 -0
  47. package/dist/core/logger.d.ts +17 -0
  48. package/dist/core/logger.d.ts.map +1 -0
  49. package/dist/core/logger.js +66 -0
  50. package/dist/core/pkce.d.ts +21 -0
  51. package/dist/core/pkce.d.ts.map +1 -0
  52. package/dist/core/pkce.js +27 -0
  53. package/dist/facades/owox-token-facade.d.ts +27 -0
  54. package/dist/facades/owox-token-facade.d.ts.map +1 -0
  55. package/dist/facades/owox-token-facade.js +117 -0
  56. package/dist/index.d.ts +13 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +13 -0
  59. package/dist/jwt/jwksCache.d.ts +24 -0
  60. package/dist/jwt/jwksCache.d.ts.map +1 -0
  61. package/dist/jwt/jwksCache.js +41 -0
  62. package/dist/jwt/parseToken.d.ts +15 -0
  63. package/dist/jwt/parseToken.d.ts.map +1 -0
  64. package/dist/jwt/parseToken.js +26 -0
  65. package/dist/jwt/verifyJwt.d.ts +13 -0
  66. package/dist/jwt/verifyJwt.d.ts.map +1 -0
  67. package/dist/jwt/verifyJwt.js +23 -0
  68. package/dist/mappers/client-payload-mapper.d.ts +6 -0
  69. package/dist/mappers/client-payload-mapper.d.ts.map +1 -0
  70. package/dist/mappers/client-payload-mapper.js +17 -0
  71. package/dist/mappers/user-info-payload-builder.d.ts +11 -0
  72. package/dist/mappers/user-info-payload-builder.d.ts.map +1 -0
  73. package/dist/mappers/user-info-payload-builder.js +28 -0
  74. package/dist/owox-better-auth-idp.d.ts +40 -0
  75. package/dist/owox-better-auth-idp.d.ts.map +1 -0
  76. package/dist/owox-better-auth-idp.js +239 -0
  77. package/dist/resources/templates/layouts/auth.ejs +29 -0
  78. package/dist/resources/templates/pages/sign-in.ejs +66 -0
  79. package/dist/resources/templates/pages/sign-up.ejs +65 -0
  80. package/dist/resources/templates/partials/brand-panel.ejs +24 -0
  81. package/dist/resources/templates/partials/footer.ejs +10 -0
  82. package/dist/resources/templates/partials/head.ejs +64 -0
  83. package/dist/resources/templates/partials/header.ejs +7 -0
  84. package/dist/services/auth/better-auth-session-service.d.ts +28 -0
  85. package/dist/services/auth/better-auth-session-service.d.ts.map +1 -0
  86. package/dist/services/auth/better-auth-session-service.js +121 -0
  87. package/dist/services/auth/pkce-flow-orchestrator.d.ts +33 -0
  88. package/dist/services/auth/pkce-flow-orchestrator.d.ts.map +1 -0
  89. package/dist/services/auth/pkce-flow-orchestrator.js +134 -0
  90. package/dist/services/auth/platform-auth-flow-client.d.ts +16 -0
  91. package/dist/services/auth/platform-auth-flow-client.d.ts.map +1 -0
  92. package/dist/services/auth/platform-auth-flow-client.js +32 -0
  93. package/dist/services/core/token-service.d.ts +25 -0
  94. package/dist/services/core/token-service.d.ts.map +1 -0
  95. package/dist/services/core/token-service.js +56 -0
  96. package/dist/services/core/user-context-service.d.ts +23 -0
  97. package/dist/services/core/user-context-service.d.ts.map +1 -0
  98. package/dist/services/core/user-context-service.js +54 -0
  99. package/dist/services/middleware/middleware-service.d.ts +19 -0
  100. package/dist/services/middleware/middleware-service.d.ts.map +1 -0
  101. package/dist/services/middleware/middleware-service.js +62 -0
  102. package/dist/services/middleware/request-handler-service.d.ts +18 -0
  103. package/dist/services/middleware/request-handler-service.d.ts.map +1 -0
  104. package/dist/services/middleware/request-handler-service.js +131 -0
  105. package/dist/services/rendering/page-service.d.ts +11 -0
  106. package/dist/services/rendering/page-service.d.ts.map +1 -0
  107. package/dist/services/rendering/page-service.js +26 -0
  108. package/dist/services/rendering/template-service.d.ts +17 -0
  109. package/dist/services/rendering/template-service.d.ts.map +1 -0
  110. package/dist/services/rendering/template-service.js +52 -0
  111. package/dist/social/google-provider.d.ts +35 -0
  112. package/dist/social/google-provider.d.ts.map +1 -0
  113. package/dist/social/google-provider.js +55 -0
  114. package/dist/social/social-provider.d.ts +23 -0
  115. package/dist/social/social-provider.d.ts.map +1 -0
  116. package/dist/social/social-provider.js +1 -0
  117. package/dist/store/database-store-factory.d.ts +8 -0
  118. package/dist/store/database-store-factory.d.ts.map +1 -0
  119. package/dist/store/database-store-factory.js +38 -0
  120. package/dist/store/database-store.d.ts +20 -0
  121. package/dist/store/database-store.d.ts.map +1 -0
  122. package/dist/store/database-store.js +1 -0
  123. package/dist/store/mysql-database-store.d.ts +40 -0
  124. package/dist/store/mysql-database-store.d.ts.map +1 -0
  125. package/dist/store/mysql-database-store.js +213 -0
  126. package/dist/store/sqlite-database-store.d.ts +32 -0
  127. package/dist/store/sqlite-database-store.d.ts.map +1 -0
  128. package/dist/store/sqlite-database-store.js +205 -0
  129. package/dist/store/store-result.d.ts +16 -0
  130. package/dist/store/store-result.d.ts.map +1 -0
  131. package/dist/store/store-result.js +25 -0
  132. package/dist/types/auth-request-context.d.ts +15 -0
  133. package/dist/types/auth-request-context.d.ts.map +1 -0
  134. package/dist/types/auth-request-context.js +12 -0
  135. package/dist/types/auth-session.d.ts +25 -0
  136. package/dist/types/auth-session.d.ts.map +1 -0
  137. package/dist/types/auth-session.js +1 -0
  138. package/dist/types/database-models.d.ts +39 -0
  139. package/dist/types/database-models.d.ts.map +1 -0
  140. package/dist/types/database-models.js +1 -0
  141. package/dist/types/index.d.ts +45 -0
  142. package/dist/types/index.d.ts.map +1 -0
  143. package/dist/types/index.js +2 -0
  144. package/dist/utils/cookie-policy.d.ts +16 -0
  145. package/dist/utils/cookie-policy.d.ts.map +1 -0
  146. package/dist/utils/cookie-policy.js +27 -0
  147. package/dist/utils/platform-redirect-builder.d.ts +29 -0
  148. package/dist/utils/platform-redirect-builder.d.ts.map +1 -0
  149. package/dist/utils/platform-redirect-builder.js +86 -0
  150. package/dist/utils/request-utils.d.ts +87 -0
  151. package/dist/utils/request-utils.d.ts.map +1 -0
  152. package/dist/utils/request-utils.js +171 -0
  153. package/dist/utils/string-utils.d.ts +13 -0
  154. package/dist/utils/string-utils.d.ts.map +1 -0
  155. package/dist/utils/string-utils.js +21 -0
  156. package/package.json +71 -0
@@ -0,0 +1,45 @@
1
+ import type { PoolOptions } from 'mysql2';
2
+ /**
3
+ * SQLite database configuration
4
+ */
5
+ export interface SqliteConfig {
6
+ type: 'sqlite';
7
+ filename: string;
8
+ }
9
+ /**
10
+ * MySQL database configuration
11
+ */
12
+ export interface MySqlConfig {
13
+ type: 'mysql';
14
+ host: string;
15
+ user: string;
16
+ password: string;
17
+ database: string;
18
+ port: number | undefined;
19
+ ssl?: PoolOptions['ssl'];
20
+ connectionLimit: number | undefined;
21
+ }
22
+ export interface GoogleProviderConfig {
23
+ clientId: string;
24
+ clientSecret: string;
25
+ redirectURI?: string;
26
+ prompt?: string;
27
+ accessType?: string;
28
+ }
29
+ export interface SocialProvidersConfig {
30
+ google?: GoogleProviderConfig;
31
+ }
32
+ export type DatabaseConfig = SqliteConfig | MySqlConfig;
33
+ export interface BetterAuthConfig {
34
+ database: DatabaseConfig;
35
+ socialProviders?: SocialProvidersConfig;
36
+ session?: {
37
+ maxAge?: number;
38
+ };
39
+ trustedOrigins?: string[];
40
+ baseURL?: string;
41
+ secret: string;
42
+ }
43
+ export * from './auth-session.js';
44
+ export * from './database-models.js';
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,GAAG,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CAC/B;AAED,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,WAAW,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,cAAc,CAAC;IACzB,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACxC,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './auth-session.js';
2
+ export * from './database-models.js';
@@ -0,0 +1,16 @@
1
+ import type { CookieOptions, Request, Response } from 'express';
2
+ /** Default cookie path for auth cookies. */
3
+ export declare const COOKIE_DEFAULT_PATH = "/";
4
+ /** Determines if a request should use secure cookies. */
5
+ export declare const isSecureRequest: (req: Request) => boolean;
6
+ /** Builds cookie options using consistent security defaults. */
7
+ export declare function buildCookieOptions(req: Request, options?: {
8
+ maxAgeMs?: number;
9
+ }): CookieOptions;
10
+ /** Sets a cookie using shared defaults. */
11
+ export declare function setCookie(res: Response, req: Request, name: string, value: string, options?: {
12
+ maxAgeMs?: number;
13
+ }): void;
14
+ /** Clears a cookie, optionally using the same security flags as set. */
15
+ export declare function clearCookie(res: Response, name: string, req?: Request): void;
16
+ //# sourceMappingURL=cookie-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie-policy.d.ts","sourceRoot":"","sources":["../../src/utils/cookie-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEhE,4CAA4C;AAC5C,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAIvC,yDAAyD;AACzD,eAAO,MAAM,eAAe,GAAI,KAAK,OAAO,KAAG,OACQ,CAAC;AAExD,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAQ/F;AAED,2CAA2C;AAC3C,wBAAgB,SAAS,CACvB,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9B,IAAI,CAEN;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAM5E"}
@@ -0,0 +1,27 @@
1
+ /** Default cookie path for auth cookies. */
2
+ export const COOKIE_DEFAULT_PATH = '/';
3
+ const isLocalhost = (host) => host === 'localhost' || host === '127.0.0.1';
4
+ /** Determines if a request should use secure cookies. */
5
+ export const isSecureRequest = (req) => req.protocol !== 'http' && !isLocalhost(req.hostname);
6
+ /** Builds cookie options using consistent security defaults. */
7
+ export function buildCookieOptions(req, options) {
8
+ return {
9
+ httpOnly: true,
10
+ sameSite: 'lax',
11
+ path: COOKIE_DEFAULT_PATH,
12
+ secure: isSecureRequest(req),
13
+ ...(options?.maxAgeMs ? { maxAge: options.maxAgeMs } : {}),
14
+ };
15
+ }
16
+ /** Sets a cookie using shared defaults. */
17
+ export function setCookie(res, req, name, value, options) {
18
+ res.cookie(name, value, buildCookieOptions(req, options));
19
+ }
20
+ /** Clears a cookie, optionally using the same security flags as set. */
21
+ export function clearCookie(res, name, req) {
22
+ if (req) {
23
+ res.clearCookie(name, buildCookieOptions(req));
24
+ return;
25
+ }
26
+ res.clearCookie(name, { path: COOKIE_DEFAULT_PATH });
27
+ }
@@ -0,0 +1,29 @@
1
+ import { PlatformParams } from './request-utils.js';
2
+ export interface PlatformRedirectOptions {
3
+ baseUrl?: string | null;
4
+ signInUrl?: string | null;
5
+ code: string;
6
+ state: string;
7
+ params?: PlatformParams;
8
+ defaultSource?: string;
9
+ allowedRedirectOrigins?: string[];
10
+ }
11
+ export interface PlatformEntryOptions {
12
+ authUrl: string;
13
+ params?: PlatformParams;
14
+ defaultSource?: string;
15
+ allowedRedirectOrigins?: string[];
16
+ }
17
+ /**
18
+ * Sanitizes redirect parameters to avoid open redirects.
19
+ */
20
+ export declare function sanitizeRedirectParam(value: string | undefined, allowedRedirectOrigins: string[] | undefined): string | undefined;
21
+ /**
22
+ * Builds a Platform redirect URL with code/state and safe params.
23
+ */
24
+ export declare function buildPlatformRedirectUrl(options: PlatformRedirectOptions): URL | null;
25
+ /**
26
+ * Builds a Platform entry URL (sign-in or sign-up) with safe params.
27
+ */
28
+ export declare function buildPlatformEntryUrl(options: PlatformEntryOptions): URL;
29
+ //# sourceMappingURL=platform-redirect-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-redirect-builder.d.ts","sourceRoot":"","sources":["../../src/utils/platform-redirect-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AAcD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,sBAAsB,EAAE,MAAM,EAAE,GAAG,SAAS,GAC3C,MAAM,GAAG,SAAS,CAQpB;AAkCD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,uBAAuB,GAAG,GAAG,GAAG,IAAI,CAcrF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,GAAG,CAOxE"}
@@ -0,0 +1,86 @@
1
+ function isRelativePath(value) {
2
+ return value.startsWith('/') && !value.startsWith('//');
3
+ }
4
+ function normalizeOrigin(value) {
5
+ try {
6
+ return new URL(value).origin;
7
+ }
8
+ catch {
9
+ return null;
10
+ }
11
+ }
12
+ /**
13
+ * Sanitizes redirect parameters to avoid open redirects.
14
+ */
15
+ export function sanitizeRedirectParam(value, allowedRedirectOrigins) {
16
+ if (!value)
17
+ return undefined;
18
+ const trimmed = value.trim();
19
+ if (!trimmed)
20
+ return undefined;
21
+ if (isRelativePath(trimmed))
22
+ return trimmed;
23
+ const origin = normalizeOrigin(trimmed);
24
+ if (!origin || !allowedRedirectOrigins?.length)
25
+ return undefined;
26
+ return allowedRedirectOrigins.includes(origin) ? trimmed : undefined;
27
+ }
28
+ function applyPlatformParams(url, params, options) {
29
+ const source = params?.source || options.defaultSource;
30
+ if (source)
31
+ url.searchParams.set('source', source);
32
+ const redirectTo = sanitizeRedirectParam(params?.redirectTo, options.allowedRedirectOrigins);
33
+ if (redirectTo)
34
+ url.searchParams.set('redirect-to', redirectTo);
35
+ const appRedirectTo = sanitizeRedirectParam(params?.appRedirectTo, options.allowedRedirectOrigins);
36
+ if (appRedirectTo)
37
+ url.searchParams.set('app-redirect-to', appRedirectTo);
38
+ if (params?.clientId)
39
+ url.searchParams.set('clientId', params.clientId);
40
+ if (params?.codeChallenge)
41
+ url.searchParams.set('codeChallenge', params.codeChallenge);
42
+ if (params?.projectId)
43
+ url.searchParams.set('projectId', params.projectId);
44
+ }
45
+ function resolveBaseUrl(baseUrl, signInUrl) {
46
+ if (baseUrl)
47
+ return baseUrl;
48
+ if (!signInUrl)
49
+ return null;
50
+ try {
51
+ const origin = new URL(signInUrl);
52
+ origin.pathname = '/ui/p/signin';
53
+ origin.search = '';
54
+ return origin.toString();
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ }
60
+ /**
61
+ * Builds a Platform redirect URL with code/state and safe params.
62
+ */
63
+ export function buildPlatformRedirectUrl(options) {
64
+ const base = resolveBaseUrl(options.baseUrl, options.signInUrl);
65
+ if (!base)
66
+ return null;
67
+ const url = new URL(base);
68
+ url.searchParams.set('code', options.code);
69
+ url.searchParams.set('state', options.state);
70
+ applyPlatformParams(url, options.params, {
71
+ defaultSource: options.defaultSource,
72
+ allowedRedirectOrigins: options.allowedRedirectOrigins,
73
+ });
74
+ return url;
75
+ }
76
+ /**
77
+ * Builds a Platform entry URL (sign-in or sign-up) with safe params.
78
+ */
79
+ export function buildPlatformEntryUrl(options) {
80
+ const url = new URL(options.authUrl);
81
+ applyPlatformParams(url, options.params, {
82
+ defaultSource: options.defaultSource,
83
+ allowedRedirectOrigins: options.allowedRedirectOrigins,
84
+ });
85
+ return url;
86
+ }
@@ -0,0 +1,87 @@
1
+ import { type Request, type Response } from 'express';
2
+ export { setCookie } from './cookie-policy.js';
3
+ /**
4
+ * Parameters used for Platform redirects and context persistence.
5
+ */
6
+ export interface PlatformParams {
7
+ redirectTo?: string;
8
+ appRedirectTo?: string;
9
+ source?: string;
10
+ clientId?: string;
11
+ codeChallenge?: string;
12
+ projectId?: string;
13
+ }
14
+ /**
15
+ * Centralized state handling with single-source validation.
16
+ */
17
+ export declare class StateManager {
18
+ private readonly req;
19
+ private readonly stateFromCookie;
20
+ private readonly queryState;
21
+ constructor(req: Request);
22
+ extract(): string;
23
+ extractFromCookie(): string;
24
+ hasMismatch(): boolean;
25
+ persist(res: Response, state: string): void;
26
+ }
27
+ declare module 'express' {
28
+ interface Request {
29
+ _stateManager?: StateManager;
30
+ }
31
+ }
32
+ /**
33
+ * Returns a cached StateManager instance for the request.
34
+ */
35
+ export declare function getStateManager(req: Request): StateManager;
36
+ /**
37
+ * Reads a cookie value from request headers or cookie parser.
38
+ */
39
+ export declare function getCookie(req: Request, name: string): string | undefined;
40
+ /**
41
+ * Clears Platform flow cookies (state and params).
42
+ */
43
+ export declare function clearPlatformCookies(res: Response, req?: Request): void;
44
+ /**
45
+ * Clears Better Auth session and CSRF cookies.
46
+ */
47
+ export declare function clearBetterAuthCookies(res: Response, req?: Request): void;
48
+ /**
49
+ * Clears all auth-related cookies (Platform + Better Auth).
50
+ */
51
+ export declare function clearAllAuthCookies(res: Response, req?: Request): void;
52
+ /**
53
+ * Persists the PKCE state into a cookie.
54
+ */
55
+ export declare function persistStateCookie(req: Request, res: Response, state: string): void;
56
+ /**
57
+ * Extracts state from cookie or query, with mismatch protection.
58
+ */
59
+ export declare function extractState(req: Request): string;
60
+ /**
61
+ * Extracts state only from the cookie.
62
+ */
63
+ export declare function extractStateFromCookie(req: Request): string;
64
+ /**
65
+ * Returns true when cookie state and query state mismatch.
66
+ */
67
+ export declare function hasStateMismatch(req: Request): boolean;
68
+ /**
69
+ * Extracts redirect parameters from cookie or query.
70
+ */
71
+ export declare function extractPlatformParams(req: Request): PlatformParams;
72
+ /**
73
+ * Persists redirect parameters into a cookie.
74
+ */
75
+ export declare function persistPlatformParams(req: Request, res: Response, params: PlatformParams): void;
76
+ /**
77
+ * Persists both state and redirect parameters into cookies.
78
+ */
79
+ export declare function persistPlatformContext(req: Request, res: Response, context: {
80
+ state?: string;
81
+ params: PlatformParams;
82
+ }): void;
83
+ /**
84
+ * Extracts the core refresh token from cookies.
85
+ */
86
+ export declare const extractRefreshToken: (req: Request) => string | undefined;
87
+ //# sourceMappingURL=request-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-utils.d.ts","sourceRoot":"","sources":["../../src/utils/request-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQtD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;GAEG;AACH,qBAAa,YAAY;IAIX,OAAO,CAAC,QAAQ,CAAC,GAAG;IAHhC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAEP,GAAG,EAAE,OAAO;IAKzC,OAAO,IAAI,MAAM;IAOjB,iBAAiB,IAAI,MAAM;IAI3B,WAAW,IAAI,OAAO;IAMtB,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAI5C;AAED,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,OAAO;QACf,aAAa,CAAC,EAAE,YAAY,CAAC;KAC9B;CACF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CAK1D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAkBxE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAGvE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAIzE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,OAAO,GAAG,IAAI,CAGtE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEnF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAEjD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE3D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAqClE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAO/F;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,OAAO,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAClD,IAAI,CAKN;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,OAAO,KAAG,MAAM,GAAG,SACjB,CAAC"}
@@ -0,0 +1,171 @@
1
+ import { BETTER_AUTH_CSRF_COOKIE, BETTER_AUTH_SESSION_COOKIE, BETTER_AUTH_STATE_COOKIE, CORE_REFRESH_TOKEN_COOKIE, } from '../core/constants.js';
2
+ import { clearCookie, setCookie } from './cookie-policy.js';
3
+ export { setCookie } from './cookie-policy.js';
4
+ const STATE_COOKIE = 'idp-owox-state';
5
+ const PLATFORM_PARAMS_COOKIE = 'idp-owox-params';
6
+ /**
7
+ * Centralized state handling with single-source validation.
8
+ */
9
+ export class StateManager {
10
+ req;
11
+ stateFromCookie;
12
+ queryState;
13
+ constructor(req) {
14
+ this.req = req;
15
+ this.stateFromCookie = getCookie(req, STATE_COOKIE);
16
+ this.queryState = typeof req.query?.state === 'string' ? req.query.state : '';
17
+ }
18
+ extract() {
19
+ if (this.hasMismatch()) {
20
+ return '';
21
+ }
22
+ return this.stateFromCookie || this.queryState || '';
23
+ }
24
+ extractFromCookie() {
25
+ return this.stateFromCookie || '';
26
+ }
27
+ hasMismatch() {
28
+ return Boolean(this.stateFromCookie && this.queryState && this.stateFromCookie !== this.queryState);
29
+ }
30
+ persist(res, state) {
31
+ if (!state)
32
+ return;
33
+ setCookie(res, this.req, STATE_COOKIE, state);
34
+ }
35
+ }
36
+ /**
37
+ * Returns a cached StateManager instance for the request.
38
+ */
39
+ export function getStateManager(req) {
40
+ if (!req._stateManager) {
41
+ req._stateManager = new StateManager(req);
42
+ }
43
+ return req._stateManager;
44
+ }
45
+ /**
46
+ * Reads a cookie value from request headers or cookie parser.
47
+ */
48
+ export function getCookie(req, name) {
49
+ const cookies = req.cookies;
50
+ if (cookies && typeof cookies[name] === 'string') {
51
+ return cookies[name];
52
+ }
53
+ const cookieHeader = req.headers.cookie || '';
54
+ if (!cookieHeader)
55
+ return undefined;
56
+ const escapedName = encodeURIComponent(name).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
57
+ const match = cookieHeader.match(new RegExp(`(?:^|;\\s*)${escapedName}=([^;]*)`));
58
+ if (!match || !match[1])
59
+ return undefined;
60
+ try {
61
+ return decodeURIComponent(match[1]);
62
+ }
63
+ catch {
64
+ return match[1];
65
+ }
66
+ }
67
+ /**
68
+ * Clears Platform flow cookies (state and params).
69
+ */
70
+ export function clearPlatformCookies(res, req) {
71
+ clearCookie(res, STATE_COOKIE, req);
72
+ clearCookie(res, PLATFORM_PARAMS_COOKIE, req);
73
+ }
74
+ /**
75
+ * Clears Better Auth session and CSRF cookies.
76
+ */
77
+ export function clearBetterAuthCookies(res, req) {
78
+ clearCookie(res, BETTER_AUTH_SESSION_COOKIE, req);
79
+ clearCookie(res, BETTER_AUTH_CSRF_COOKIE, req);
80
+ clearCookie(res, BETTER_AUTH_STATE_COOKIE, req);
81
+ }
82
+ /**
83
+ * Clears all auth-related cookies (Platform + Better Auth).
84
+ */
85
+ export function clearAllAuthCookies(res, req) {
86
+ clearPlatformCookies(res, req);
87
+ clearBetterAuthCookies(res, req);
88
+ }
89
+ /**
90
+ * Persists the PKCE state into a cookie.
91
+ */
92
+ export function persistStateCookie(req, res, state) {
93
+ getStateManager(req).persist(res, state);
94
+ }
95
+ /**
96
+ * Extracts state from cookie or query, with mismatch protection.
97
+ */
98
+ export function extractState(req) {
99
+ return getStateManager(req).extract();
100
+ }
101
+ /**
102
+ * Extracts state only from the cookie.
103
+ */
104
+ export function extractStateFromCookie(req) {
105
+ return getStateManager(req).extractFromCookie();
106
+ }
107
+ /**
108
+ * Returns true when cookie state and query state mismatch.
109
+ */
110
+ export function hasStateMismatch(req) {
111
+ return getStateManager(req).hasMismatch();
112
+ }
113
+ /**
114
+ * Extracts redirect parameters from cookie or query.
115
+ */
116
+ export function extractPlatformParams(req) {
117
+ const cookiePayload = getCookie(req, PLATFORM_PARAMS_COOKIE);
118
+ if (cookiePayload) {
119
+ try {
120
+ const parsed = JSON.parse(decodeURIComponent(cookiePayload));
121
+ return {
122
+ redirectTo: parsed.redirectTo,
123
+ appRedirectTo: parsed.appRedirectTo,
124
+ source: parsed.source,
125
+ clientId: parsed.clientId,
126
+ codeChallenge: parsed.codeChallenge,
127
+ projectId: parsed.projectId,
128
+ };
129
+ }
130
+ catch {
131
+ // ignore malformed cookie
132
+ }
133
+ }
134
+ const redirectTo = (typeof req.query?.['redirect-to'] === 'string' && req.query['redirect-to']) ||
135
+ (typeof req.query?.redirectTo === 'string' && req.query.redirectTo) ||
136
+ undefined;
137
+ const appRedirectTo = (typeof req.query?.['app-redirect-to'] === 'string' && req.query['app-redirect-to']) ||
138
+ undefined;
139
+ const source = typeof req.query?.source === 'string' ? req.query.source : undefined;
140
+ const clientId = typeof req.query?.clientId === 'string' ? req.query.clientId : undefined;
141
+ const codeChallenge = (typeof req.query?.codeChallenge === 'string' && req.query.codeChallenge) ||
142
+ (typeof req.query?.codechallenge === 'string' && req.query.codechallenge) ||
143
+ undefined;
144
+ const projectId = typeof req.query?.projectId === 'string' ? req.query.projectId : undefined;
145
+ return { redirectTo, appRedirectTo, source, clientId, codeChallenge, projectId };
146
+ }
147
+ /**
148
+ * Persists redirect parameters into a cookie.
149
+ */
150
+ export function persistPlatformParams(req, res, params) {
151
+ try {
152
+ const serialized = encodeURIComponent(JSON.stringify(params));
153
+ setCookie(res, req, PLATFORM_PARAMS_COOKIE, serialized);
154
+ }
155
+ catch {
156
+ // ignore serialization issues
157
+ }
158
+ }
159
+ /**
160
+ * Persists both state and redirect parameters into cookies.
161
+ */
162
+ export function persistPlatformContext(req, res, context) {
163
+ persistPlatformParams(req, res, context.params);
164
+ if (context.state) {
165
+ persistStateCookie(req, res, context.state);
166
+ }
167
+ }
168
+ /**
169
+ * Extracts the core refresh token from cookies.
170
+ */
171
+ export const extractRefreshToken = (req) => getCookie(req, CORE_REFRESH_TOKEN_COOKIE);
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Splits a full name into first/last parts.
3
+ */
4
+ export declare function splitName(name?: string): {
5
+ firstName: string;
6
+ lastName: string;
7
+ fullName: string;
8
+ };
9
+ /**
10
+ * Formats an error into a readable string with stack.
11
+ */
12
+ export declare function formatError(error: unknown): string;
13
+ //# sourceMappingURL=string-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string-utils.d.ts","sourceRoot":"","sources":["../../src/utils/string-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAQA;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKlD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Splits a full name into first/last parts.
3
+ */
4
+ export function splitName(name) {
5
+ const cleaned = (name || '').trim();
6
+ if (!cleaned) {
7
+ return { firstName: '', lastName: '', fullName: '' };
8
+ }
9
+ const [firstName = '', ...rest] = cleaned.split(/\s+/);
10
+ const lastName = rest.join(' ');
11
+ return { firstName, lastName, fullName: cleaned };
12
+ }
13
+ /**
14
+ * Formats an error into a readable string with stack.
15
+ */
16
+ export function formatError(error) {
17
+ if (error instanceof Error) {
18
+ return `${error.message}\n${error.stack ?? ''}`;
19
+ }
20
+ return String(error);
21
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@owox/idp-owox-better-auth",
3
+ "version": "0.18.0",
4
+ "type": "module",
5
+ "author": "OWOX",
6
+ "license": "ELv2",
7
+ "description": "OWOX Better Auth implementation for OWOX IDP Protocol",
8
+ "scripts": {
9
+ "build": "tsc && node ./scripts/copy-public.cjs",
10
+ "build:dep": "npm run build:internal-helpers && npm run build:idp-protocol",
11
+ "build:idp-protocol": "npm run build -w @owox/idp-protocol --prefix ../..",
12
+ "build:internal-helpers": "npm run build -w @owox/internal-helpers --prefix ../..",
13
+ "clean": "shx rm -rf dist",
14
+ "test": "jest",
15
+ "lint": "eslint . --config ./eslint.config.js",
16
+ "lint:fix": "eslint . --fix --config ./eslint.config.js",
17
+ "format": "prettier --write \"**/*.{ts,js,json,md}\" --ignore-path ../../.prettierignore",
18
+ "format:check": "prettier --check \"**/*.{ts,js,json,md}\" --ignore-path ../../.prettierignore",
19
+ "typecheck": "tsc --noEmit",
20
+ "prepublishOnly": "npm run lint && npm run typecheck"
21
+ },
22
+ "peerDependencies": {
23
+ "express": "^5",
24
+ "zod": "^3.25"
25
+ },
26
+ "dependencies": {
27
+ "@owox/idp-protocol": "0.18.0",
28
+ "@owox/internal-helpers": "0.18.0",
29
+ "axios": "^1.11.0",
30
+ "better-auth": "^1.4.18",
31
+ "cookie-parser": "^1.4.7",
32
+ "ejs": "^3.1.10",
33
+ "env-paths": "^3.0.0",
34
+ "jose": "^6.0.12",
35
+ "ms": "^2.1.3",
36
+ "mysql2": "^3.14.3",
37
+ "better-sqlite3": "^12.2.0",
38
+ "pkce-challenge": "^5.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "@owox/eslint-config": "*",
42
+ "@owox/prettier-config": "*",
43
+ "@owox/typescript-config": "*",
44
+ "@types/better-sqlite3": "^7.6.13",
45
+ "@types/cookie-parser": "^1.4.9",
46
+ "@types/ejs": "^3.1.5",
47
+ "@types/express": "^5.0.0",
48
+ "@types/jest": "^29.5.14",
49
+ "@types/node": "^22.10.7",
50
+ "jest": "^30.2.0",
51
+ "ts-jest": "^29.4.6"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ },
56
+ "engines": {
57
+ "node": ">=22.16.0"
58
+ },
59
+ "files": [
60
+ "dist"
61
+ ],
62
+ "exports": {
63
+ ".": {
64
+ "import": "./dist/index.js",
65
+ "require": "./dist/index.js",
66
+ "types": "./dist/index.d.ts"
67
+ }
68
+ },
69
+ "main": "./dist/index.js",
70
+ "types": "./dist/index.d.ts"
71
+ }