@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,65 @@
1
+ <!-- Sign Up Content -->
2
+ <div class="space-y-6">
3
+ <!-- Message -->
4
+ <p class="text-center text-sm text-muted-foreground">
5
+ Be confident that your data is protected by Google's infrastructure security standards.
6
+ </p>
7
+
8
+ <!-- Sign up button -->
9
+ <button
10
+ id="google-signup"
11
+ type="button"
12
+ class="w-full inline-flex justify-center items-center gap-2 py-2 px-4 border border-border rounded-md text-sm font-medium text-foreground bg-background hover:bg-muted transition-colors"
13
+ >
14
+ <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" x="0px" y="0px" viewBox="0 0 48 48">
15
+ <path fill="#FFC107" d="M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"></path><path fill="#FF3D00" d="M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"></path>
16
+ <path fill="#4CAF50" d="M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"></path>
17
+ <path fill="#1976D2" d="M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571c0.001-0.001,0.002-0.001,0.003-0.002l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"></path>
18
+ </svg>
19
+ <span>Sign up with Google</span>
20
+ </button>
21
+
22
+ <!-- Sign in link -->
23
+ <p class="text-center text-sm text-muted-foreground">
24
+ Already have an account?
25
+ <a href="/auth/sign-in" class="font-medium text-primary hover:text-primary/80">Sign in</a>
26
+ </p>
27
+ </div>
28
+
29
+ <script>
30
+ const urlParams = new URLSearchParams(window.location.search);
31
+ const redirectValue = urlParams.get('redirect') || '/';
32
+ const googleButton = document.getElementById('google-signup');
33
+ const redirectTarget = redirectValue || '/';
34
+
35
+ async function startSocial(provider) {
36
+ try {
37
+ const response = await fetch('/auth/better-auth/sign-in/social', {
38
+ method: 'POST',
39
+ headers: { 'Content-Type': 'application/json' },
40
+ body: JSON.stringify({ provider, callbackURL: redirectTarget }),
41
+ redirect: 'follow',
42
+ });
43
+
44
+ if (response.redirected) {
45
+ window.location.href = response.url;
46
+ return;
47
+ }
48
+
49
+ const contentType = response.headers.get('content-type') || '';
50
+ if (contentType.includes('application/json')) {
51
+ const data = await response.json();
52
+ if (data?.url) {
53
+ window.location.href = data.url;
54
+ return;
55
+ }
56
+ }
57
+
58
+ window.location.reload();
59
+ } catch (err) {
60
+ console.error('Social signup failed', err);
61
+ }
62
+ }
63
+
64
+ googleButton?.addEventListener('click', () => startSocial('google'));
65
+ </script>
@@ -0,0 +1,24 @@
1
+ <!-- Left Brand Panel -->
2
+ <div
3
+ class="flex flex-col items-center justify-center h-full rounded-l-lg relative overflow-hidden"
4
+ style="background: rgba(30, 136, 229, 0.1) url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTc2IiBoZWlnaHQ9IjQwMCIgdmlld0JveD0iMCAwIDE3NiA0MDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2ZfMTgyMl8xNjUzMCkiPgo8cGF0aCBkPSJNMTU1LjI5MyAyNTUuNjEzSDE5NS43MDdMMTgzLjEwNCAxODIuMjc5QzE4OS42NTUgMTgwLjA3MiAxOTUuMDggMTc2LjI4IDE5OS4zOCAxNzAuOTAzQzIwMy42ODEgMTY1LjUyNyAyMDUuODMxIDE1OS4zNTUgMjA1LjgzMSAxNTIuMzg3QzIwNS44MzEgMTQzLjg3MSAyMDIuODkgMTM2LjY1MiAxOTcuMDEgMTMwLjczMUMxOTEuMTI4IDEyNC44MSAxODMuOTU4IDEyMS44NDkgMTc1LjUgMTIxLjg0OUMxNjcuMDQyIDEyMS44NDkgMTU5Ljg3MiAxMjQuODEgMTUzLjk5IDEzMC43MzFDMTQ4LjExIDEzNi42NTIgMTQ1LjE2OSAxNDMuODcxIDE0NS4xNjkgMTUyLjM4N0MxNDUuMTY5IDE1OS4zNTUgMTQ3LjMxOSAxNjUuNTI3IDE1MS42MiAxNzAuOTAzQzE1NS45MiAxNzYuMjggMTYxLjM0NSAxODAuMDcyIDE2Ny44OTYgMTgyLjI3OUwxNTUuMjkzIDI1NS42MTNaTTE3NS41IDQwMEMxMzAuNzg3IDM4Ni4zOCA5My42OTE2IDM1OC44MTcgNjQuMjE0OCAzMTcuMzEyQzM0LjczODIgMjc1LjgwNiAyMCAyMjkuMzA1IDIwIDE3Ny44MDZWNTguNDk0NEwxNzUuNSAwTDMzMSA1OC40OTQ0VjE3Ny44MDZDMzMxIDIyOS4zMDUgMzE2LjI2MiAyNzUuODA2IDI4Ni43ODUgMzE3LjMxMkMyNTcuMzA4IDM1OC44MTcgMjIwLjIxMyAzODYuMzggMTc1LjUgNDAwWk0xNzUuNSAzODEuNjc4QzIxNS43OTkgMzY4LjY2IDI0OC45NDIgMzQzLjEzMyAyNzQuOTMxIDMwNS4wOTdDMzAwLjkxOCAyNjcuMDYxIDMxMy45MTIgMjI0LjYzMSAzMTMuOTEyIDE3Ny44MDZWNzAuMzY1NUwxNzUuNSAxOC4xNTA4TDM3LjA4NzggNzAuMzY1NVYxNzcuODA2QzM3LjA4NzggMjI0LjYzMSA1MC4wODE3IDI2Ny4wNjEgNzYuMDY5NCAzMDUuMDk3QzEwMi4wNTggMzQzLjEzMyAxMzUuMjAxIDM2OC42NiAxNzUuNSAzODEuNjc4WiIgZmlsbD0iIzFFODhFNSIgZmlsbC1vcGFjaXR5PSIwLjEiLz4KPC9nPgo8ZGVmcz4KPGZpbHRlciBpZD0iZmlsdGVyMF9mXzE4MjJfMTY1MzAiIHg9IjAiIHk9Ii0yMCIgd2lkdGg9IjM1MSIgaGVpZ2h0PSI0NDAiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz4KPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0ic2hhcGUiLz4KPGZlR2F1c3NpYW5CbHVyIHN0ZERldmlhdGlvbj0iMTAiIHJlc3VsdD0iZWZmZWN0MV9mb3JlZ3JvdW5kQmx1cl8xODIyXzE2NTMwIi8+CjwvZmlsdGVyPgo8L2RlZnM+Cjwvc3ZnPgo=') no-repeat right center; background-size: contain;"
5
+ >
6
+ <!-- Content -->
7
+ <div class="relative z-10 text-center px-8">
8
+ <!-- Logo -->
9
+ <div class="mb-6 flex justify-center">
10
+ <img
11
+ src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDUiIGhlaWdodD0iMzYiIHZpZXdCb3g9IjAgMCA0NSAzNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzEwMjZfOSkiPgo8cGF0aCBkPSJNNDEuMDEyNCAyLjcwODA4QzQyLjU4NDEgNC4yODA4NiA0My4yMzA3IDYuOTMxMzQgNDMuMjMwNyA2LjkzMTM0QzQzLjIzMDcgNi45MzEzNCA0NC4xOTI0IDEyLjI2ODYgNDQuMTkyNCAxOS41MTUyQzQ0LjE5MjQgOS4yNTc3OCA0MC43MTI2IDcuNDk3MSAyOC42MTY5IDcuNDk3MUgxNy40NjIyQzExLjI3MDIgNy40OTcxIDExLjY4OSAxMy43MiAxMS4yNzAyIDE2LjY4MTVMMTAuNzYxNCAyMS4xNTZDMTAuNTE3MSAyNS44NjM1IDExLjMzNDUgMjguNzgwNSAxNi4xNjQ0IDI4Ljc4MDVDNi4wOTM3MiAyOC43ODA1IDAuNDk5OTg3IDMwLjQyOTQgMC41IDE2LjIzMjZDMC40OTk5OTQgOS44MDcwOCAxLjQ2ODkzIDYuOTMxMzQgMS40Njg5MyA2LjkzMTM0QzEuNDY4OTMgNi45MzEzNCAyLjExNTQ4IDQuMjgwODYgMy42OTA0OCAyLjcwODA4QzUuMjY1NDkgMS4xMzM0OSA3LjU5OTggMC45NzU0NTMgNy41OTk4IDAuOTc1NDUzQzcuNTk5OCAwLjk3NTQ1MyAxMi40MTk1IDAuMjUgMjEuOTQwMyAwLjI1QzMxLjQ2MTIgMC4yNSAzNi44NCAwLjk3NTQ1MyAzNi44NCAwLjk3NTQ1M0MzNi44NCAwLjk3NTQ1MyAzOS40MzU5IDEuMTMzNDkgNDEuMDEyNCAyLjcwODA4WiIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyXzEwMjZfOSkiLz4KPHBhdGggZD0iTTQ0LjE5MDcgMTkuODQxMkM0NC4xOTEzIDE5Ljk2OTUgNDQuMTkxNiAyMC4wOTg5IDQ0LjE5MTYgMjAuMjI5NUM0NC4xOTE2IDI2LjM4MzcgNDMuMjc1NCAyOC43NzkgNDMuMjc1NCAyOC43NzlDNDMuMjc1NCAyOC43NzkgNDIuNTU4NCAzMS42ODA4IDQxLjMzNDMgMzIuOTM0M0MzOS4zOTE4IDM0LjkyMzMgMzcuMzE0NCAzNS4wMzQzIDM3LjMxNDQgMzUuMDM0M0MzNy4zMTQ0IDM1LjAzNDMgMzIuODQ1MyAzNS43NSAyMy4yMjkgMzUuNzVDMTQuMDAzMSAzNS43NSA3Ljg1OTIxIDM1LjAzODcgNy44NTkyMSAzNS4wMzg3QzcuODU5MjEgMzUuMDM4NyA1LjI2NTA0IDM0Ljg3OTUgMy42OTAwNCAzMy4zMDY0QzIuMTE1MDQgMzEuNzMwNyAxLjQ2ODQ5IDI4Ljc3OSAxLjQ2ODQ5IDI4Ljc3OUMxLjQ2ODQ5IDI4Ljc3OSAwLjUgMjIuNzE2MyAwLjUgMTYuMDc5NEMwLjQ5OTk4OCAyOC44NzUyIDUuMDQ0MiAyOC43OTg0IDEzLjMxNDkgMjguNjU4N0gxMy4zMTQ5QzE0LjIyMDQgMjguNjQzNCAxNS4xNzA2IDI4LjYyNzMgMTYuMTY0NCAyOC42MjczSDI3LjMxOEMzMi4yMDEzIDI4LjYyNzMgMzMuMzAzOSAyNS4wNzMxIDMzLjUxNjQgMjEuMDAyOEwzNC4wMjY3IDE0Ljc5MzRDMzQuMTYyNiAxMi4yNDA5IDMzLjgzMzcgMTAuNDI4NyAzMy4wMzM2IDkuMjYyNDFDMzIuMTYxMiA3Ljk5MDE2IDMwLjY3NDcgNy4zNDM5IDI4LjYxNjkgNy4zNDM5QzQxLjQyNTMgNy4zNDM5IDQ0LjEwMjIgOS4wNTk5OCA0NC4xOTA3IDE5Ljg0MTJaIiBmaWxsPSJ1cmwoI3BhaW50MV9saW5lYXJfMTAyNl85KSIvPgo8L2c+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMTAyNl85IiB4MT0iMjIuMjg3OCIgeTE9IjAuMjUiIHgyPSIyMi40ODE4IiB5Mj0iMzAuNTc2OCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPgo8c3RvcCBzdG9wLWNvbG9yPSIjMDVEMkZGIi8+CjxzdG9wIG9mZnNldD0iMC4xNTYyMjciIHN0b3AtY29sb3I9IiMyMUExRjEiLz4KPHN0b3Agb2Zmc2V0PSIwLjQwNzExNCIgc3RvcC1jb2xvcj0iIzFFODhFNSIvPgo8c3RvcCBvZmZzZXQ9IjAuNzIyNDgiIHN0b3AtY29sb3I9IiMxRTZFRTUiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMTgyRkZGIi8+CjwvbGluZWFyR3JhZGllbnQ+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQxX2xpbmVhcl8xMDI2XzkiIHgxPSIzLjE3NzgzIiB5MT0iMzUuNjkzNyIgeDI9IjM3LjkzODYiIHkyPSI1LjQxMDk1IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiMyNEQ4RkYiLz4KPHN0b3Agb2Zmc2V0PSIwLjE1NjIyNyIgc3RvcC1jb2xvcj0iIzIxQTFGMSIvPgo8c3RvcCBvZmZzZXQ9IjAuNDA3MTE0IiBzdG9wLWNvbG9yPSIjMUU4OEU1Ii8+CjxzdG9wIG9mZnNldD0iMC43NDkxMDYiIHN0b3AtY29sb3I9IiMxRTdBRTUiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDA0NkY5Ii8+CjwvbGluZWFyR3JhZGllbnQ+CjxjbGlwUGF0aCBpZD0iY2xpcDBfMTAyNl85Ij4KPHJlY3Qgd2lkdGg9IjQ1IiBoZWlnaHQ9IjM2IiBmaWxsPSJ3aGl0ZSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo="
12
+ width="60"
13
+ height="48"
14
+ alt="OWOX"
15
+ class="w-15 h-12"
16
+ />
17
+ </div>
18
+
19
+ <!-- Tagline -->
20
+ <p class="text-foreground text-base font-medium">
21
+ Where Data Makes Sense
22
+ </p>
23
+ </div>
24
+ </div>
@@ -0,0 +1,10 @@
1
+ <!-- Footer -->
2
+ <div class="mt-8 text-center">
3
+ <p class="text-xs text-muted-foreground">
4
+ By clicking the "Sign in with Google" button, I agree with the
5
+ <a href="https://www.owox.com/policies/terms/" target="_blank" class="text-primary hover:text-primary/80">Terms of Service</a>
6
+ and
7
+ <a href="https://www.owox.com/policies/privacy/" target="_blank" class="text-primary hover:text-primary/80">Privacy Policy</a>.
8
+ </p>
9
+ </div>
10
+
@@ -0,0 +1,64 @@
1
+ <head>
2
+ <meta charset="UTF-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4
+ <title><%= pageTitle %></title>
5
+ <script src="https://cdn.tailwindcss.com"></script>
6
+ <script>
7
+ tailwind.config = {
8
+ theme: {
9
+ extend: {
10
+ colors: {
11
+ // OWOX Design System Colors
12
+ background: "oklch(1 0 0)",
13
+ foreground: "oklch(0.3346 0.0123 279.25)",
14
+ card: "oklch(1 0 0)",
15
+ 'card-foreground': "oklch(0.3346 0.0123 279.25)",
16
+ popover: "oklch(1 0 0)",
17
+ 'popover-foreground': "oklch(0.3346 0.0123 279.25)",
18
+ primary: {
19
+ DEFAULT: "oklch(0.6179 0.2295 250.87)",
20
+ hover: "oklch(0.54 0.23 250.87)",
21
+ foreground: "oklch(0.985 0 0)",
22
+ },
23
+ secondary: {
24
+ DEFAULT: "oklch(0.97 0 0)",
25
+ foreground: "oklch(0.205 0 0)",
26
+ },
27
+ muted: {
28
+ DEFAULT: "oklch(0.97 0 0)",
29
+ foreground: "oklch(0.5148 0.0128 274.72)",
30
+ },
31
+ accent: {
32
+ DEFAULT: "oklch(0.97 0 0)",
33
+ foreground: "oklch(0.205 0 0)",
34
+ },
35
+ destructive: {
36
+ DEFAULT: "oklch(0.577 0.245 27.325)",
37
+ foreground: "oklch(0.985 0 0)",
38
+ },
39
+ border: "oklch(0.922 0 0)",
40
+ input: "oklch(0.922 0 0)",
41
+ ring: "oklch(0.708 0 0)",
42
+ success: {
43
+ DEFAULT: "oklch(0.647 0.165 142.495)",
44
+ foreground: "oklch(0.985 0 0)",
45
+ },
46
+ // Brand blue colors
47
+ 'brand-blue': {
48
+ 50: "oklch(0.985 0.03 250.87)",
49
+ 100: "oklch(0.955 0.05 250.87)",
50
+ 200: "oklch(0.9 0.08 250.87)",
51
+ 300: "oklch(0.8 0.14 250.87)",
52
+ 400: "oklch(0.7 0.19 250.87)",
53
+ 500: "oklch(0.6179 0.2295 250.87)",
54
+ 600: "oklch(0.54 0.23 250.87)",
55
+ 700: "oklch(0.44 0.2 250.87)",
56
+ 800: "oklch(0.36 0.17 250.87)",
57
+ 900: "oklch(0.28 0.14 250.87)",
58
+ },
59
+ },
60
+ },
61
+ },
62
+ }
63
+ </script>
64
+ </head>
@@ -0,0 +1,7 @@
1
+ <!-- Header -->
2
+ <div class="text-center mb-6">
3
+ <h1 class="text-2xl font-medium text-foreground">
4
+ <%= heading %>
5
+ </h1>
6
+ </div>
7
+
@@ -0,0 +1,28 @@
1
+ import { type Request } from 'express';
2
+ import { createBetterAuthConfig } from '../../config/idp-better-auth-config.js';
3
+ import type { DatabaseStore } from '../../store/database-store.js';
4
+ import { AuthSession } from '../../types/auth-session.js';
5
+ import { PlatformAuthFlowClient, type UserInfoPayload } from './platform-auth-flow-client.js';
6
+ /**
7
+ * Better Auth integration for social login and user/account lookup.
8
+ * Manages Better Auth sessions and user data.
9
+ * Core IdP tokens are handled in OwoxTokenFacade/PkceFlowOrchestrator.
10
+ */
11
+ export declare class BetterAuthSessionService {
12
+ private readonly auth;
13
+ private readonly store;
14
+ private readonly platformAuthFlowClient;
15
+ constructor(auth: Awaited<ReturnType<typeof createBetterAuthConfig>>, store: DatabaseStore, platformAuthFlowClient: PlatformAuthFlowClient);
16
+ buildUserInfoPayload(req: Request): Promise<UserInfoPayload>;
17
+ completeAuthFlow(req: Request): Promise<{
18
+ code: string;
19
+ payload: UserInfoPayload;
20
+ }>;
21
+ completeAuthFlowWithSessionToken(sessionToken: string, state: string): Promise<{
22
+ code: string;
23
+ payload: UserInfoPayload;
24
+ }>;
25
+ getSession(req: Request): Promise<AuthSession | null>;
26
+ private buildHeadersFromExpress;
27
+ }
28
+ //# sourceMappingURL=better-auth-session-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"better-auth-session-service.d.ts","sourceRoot":"","sources":["../../../src/services/auth/better-auth-session-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAIhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE1D,OAAO,EAAE,sBAAsB,EAAE,KAAK,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAE9F;;;;GAIG;AACH,qBAAa,wBAAwB;IAEjC,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,sBAAsB;gBAFtB,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC,EACxD,KAAK,EAAE,aAAa,EACpB,sBAAsB,EAAE,sBAAsB;IAG3D,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC;IA0B5D,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC;IAYnF,gCAAgC,CACpC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC;IAkChD,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA6B3D,OAAO,CAAC,uBAAuB;CAYhC"}
@@ -0,0 +1,121 @@
1
+ import { BETTER_AUTH_SESSION_COOKIE } from '../../core/constants.js';
2
+ import { logger } from '../../core/logger.js';
3
+ import { buildUserInfoPayload } from '../../mappers/user-info-payload-builder.js';
4
+ import { getStateManager } from '../../utils/request-utils.js';
5
+ /**
6
+ * Better Auth integration for social login and user/account lookup.
7
+ * Manages Better Auth sessions and user data.
8
+ * Core IdP tokens are handled in OwoxTokenFacade/PkceFlowOrchestrator.
9
+ */
10
+ export class BetterAuthSessionService {
11
+ auth;
12
+ store;
13
+ platformAuthFlowClient;
14
+ constructor(auth, store, platformAuthFlowClient) {
15
+ this.auth = auth;
16
+ this.store = store;
17
+ this.platformAuthFlowClient = platformAuthFlowClient;
18
+ }
19
+ async buildUserInfoPayload(req) {
20
+ const stateManager = getStateManager(req);
21
+ const session = await this.getSession(req);
22
+ if (session?.user) {
23
+ const [dbUser, account] = await Promise.all([
24
+ this.store.getUserById(session.user.id),
25
+ this.store.getAccountByUserId(session.user.id),
26
+ ]);
27
+ if (!account) {
28
+ throw new Error(`No account found for user ${session.user.id}`);
29
+ }
30
+ if (!dbUser) {
31
+ throw new Error(`User not found in DB for session ${session.user.id}`);
32
+ }
33
+ return buildUserInfoPayload({
34
+ state: stateManager.extract(),
35
+ user: dbUser,
36
+ account,
37
+ });
38
+ }
39
+ throw new Error('No session found for user info');
40
+ }
41
+ async completeAuthFlow(req) {
42
+ const payload = await this.buildUserInfoPayload(req);
43
+ logger.info('Sending auth flow payload', {
44
+ hasState: Boolean(payload.state),
45
+ signinProvider: payload.userInfo.signinProvider,
46
+ userId: payload.userInfo.uid,
47
+ });
48
+ const result = await this.platformAuthFlowClient.completeAuthFlow(payload);
49
+ logger.info('Integrated backend responded', { hasCode: Boolean(result.code) });
50
+ return { code: result.code, payload };
51
+ }
52
+ async completeAuthFlowWithSessionToken(sessionToken, state) {
53
+ const headers = new Headers();
54
+ headers.set('cookie', `${BETTER_AUTH_SESSION_COOKIE}=${encodeURIComponent(sessionToken)}`);
55
+ const session = await this.auth.api.getSession({ headers });
56
+ if (!session || !session.user || !session.session) {
57
+ throw new Error('Failed to resolve session from Better Auth token');
58
+ }
59
+ const dbUser = await this.store.getUserById(session.user.id);
60
+ const account = await this.store.getAccountByUserId(session.user.id);
61
+ if (!account) {
62
+ throw new Error(`No account found for user ${session.user.id}`);
63
+ }
64
+ if (!dbUser) {
65
+ throw new Error(`User not found in DB for session ${session.user.id}`);
66
+ }
67
+ const payload = buildUserInfoPayload({
68
+ state,
69
+ user: dbUser,
70
+ account,
71
+ });
72
+ logger.info('Sending auth flow payload (callback)', {
73
+ state: payload.state,
74
+ userInfo: payload.userInfo,
75
+ });
76
+ const result = await this.platformAuthFlowClient.completeAuthFlow(payload);
77
+ logger.info('Integrated backend responded (callback)', { hasCode: Boolean(result.code) });
78
+ return { code: result.code, payload };
79
+ }
80
+ async getSession(req) {
81
+ try {
82
+ const session = await this.auth.api.getSession({
83
+ headers: this.buildHeadersFromExpress(req),
84
+ });
85
+ if (!session || !session.user || !session.session) {
86
+ return null;
87
+ }
88
+ return {
89
+ user: {
90
+ id: session.user.id,
91
+ email: session.user.email,
92
+ name: session.user.name,
93
+ },
94
+ session: {
95
+ id: session.session.id,
96
+ userId: session.session.userId,
97
+ token: session.session.token,
98
+ expiresAt: session.session.expiresAt,
99
+ },
100
+ };
101
+ }
102
+ catch (error) {
103
+ logger.error('Failed to get session', {}, error);
104
+ throw new Error('Failed to get session');
105
+ }
106
+ }
107
+ buildHeadersFromExpress(req) {
108
+ const headers = new Headers();
109
+ for (const [key, value] of Object.entries(req.headers)) {
110
+ if (!value)
111
+ continue;
112
+ if (Array.isArray(value)) {
113
+ headers.set(key, value.join(', '));
114
+ }
115
+ else {
116
+ headers.set(key, String(value));
117
+ }
118
+ }
119
+ return headers;
120
+ }
121
+ }
@@ -0,0 +1,33 @@
1
+ import { Logger } from '@owox/internal-helpers';
2
+ import type { Request, Response } from 'express';
3
+ import type { IdpOwoxConfig } from '../../config/idp-owox-config.js';
4
+ import type { OwoxTokenFacade } from '../../facades/owox-token-facade.js';
5
+ import { type PlatformParams } from '../../utils/request-utils.js';
6
+ import type { BetterAuthSessionService } from '../auth/better-auth-session-service.js';
7
+ import type { UserContextService } from '../core/user-context-service.js';
8
+ import { PlatformAuthFlowClient } from './platform-auth-flow-client.js';
9
+ /**
10
+ * Orchestrates PKCE completion for Platform using core tokens or social login.
11
+ */
12
+ export declare class PkceFlowOrchestrator {
13
+ private readonly idpOwoxConfig;
14
+ private readonly tokenFacade;
15
+ private readonly userContextService;
16
+ private readonly platformAuthFlowClient;
17
+ private readonly betterAuthSessionService;
18
+ private readonly logger;
19
+ constructor(idpOwoxConfig: IdpOwoxConfig, tokenFacade: OwoxTokenFacade, userContextService: UserContextService, platformAuthFlowClient: PlatformAuthFlowClient, betterAuthSessionService: BetterAuthSessionService, logger: Logger);
20
+ /**
21
+ * Revokes refresh token and clears auth cookies before redirecting to sign-in.
22
+ */
23
+ private revokeRefreshTokenAndClearCookies;
24
+ /**
25
+ * Completes auth flow using Identity refresh token (platform fast-path).
26
+ */
27
+ completeWithIdentityRefreshToken(refreshToken: string, params: PlatformParams, req: Request, res: Response): Promise<URL | null>;
28
+ /**
29
+ * Completes auth flow using Better Auth session token received from handler response.
30
+ */
31
+ completeWithSocialSessionToken(sessionToken: string, params: PlatformParams, req: Request, res: Response): Promise<URL | null>;
32
+ }
33
+ //# sourceMappingURL=pkce-flow-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce-flow-orchestrator.d.ts","sourceRoot":"","sources":["../../../src/services/auth/pkce-flow-orchestrator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAGrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAG1E,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,8BAA8B,CAAC;AAItC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AACvF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAwB,MAAM,gCAAgC,CAAC;AAE9F;;GAEG;AACH,qBAAa,oBAAoB;IAE7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,wBAAwB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBALN,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,eAAe,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,sBAAsB,EAAE,sBAAsB,EAC9C,wBAAwB,EAAE,wBAAwB,EAClD,MAAM,EAAE,MAAM;IAGjC;;OAEG;YACW,iCAAiC;IAkB/C;;OAEG;IACG,gCAAgC,CACpC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAmDtB;;OAEG;IACG,8BAA8B,CAClC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;CAkCvB"}
@@ -0,0 +1,134 @@
1
+ import { ProtocolRoute } from '@owox/idp-protocol';
2
+ import { SOURCE } from '../../core/constants.js';
3
+ import { AuthenticationException, isStateExpiredError } from '../../core/exceptions.js';
4
+ import { buildUserInfoPayload } from '../../mappers/user-info-payload-builder.js';
5
+ import { buildPlatformRedirectUrl } from '../../utils/platform-redirect-builder.js';
6
+ import { clearAllAuthCookies, clearBetterAuthCookies, extractState, extractStateFromCookie, } from '../../utils/request-utils.js';
7
+ import { clearCookie } from '../../utils/cookie-policy.js';
8
+ import { CORE_REFRESH_TOKEN_COOKIE } from '../../core/constants.js';
9
+ import { formatError } from '../../utils/string-utils.js';
10
+ /**
11
+ * Orchestrates PKCE completion for Platform using core tokens or social login.
12
+ */
13
+ export class PkceFlowOrchestrator {
14
+ idpOwoxConfig;
15
+ tokenFacade;
16
+ userContextService;
17
+ platformAuthFlowClient;
18
+ betterAuthSessionService;
19
+ logger;
20
+ constructor(idpOwoxConfig, tokenFacade, userContextService, platformAuthFlowClient, betterAuthSessionService, logger) {
21
+ this.idpOwoxConfig = idpOwoxConfig;
22
+ this.tokenFacade = tokenFacade;
23
+ this.userContextService = userContextService;
24
+ this.platformAuthFlowClient = platformAuthFlowClient;
25
+ this.betterAuthSessionService = betterAuthSessionService;
26
+ this.logger = logger;
27
+ }
28
+ /**
29
+ * Revokes refresh token and clears auth cookies before redirecting to sign-in.
30
+ */
31
+ async revokeRefreshTokenAndClearCookies(refreshToken, req, res) {
32
+ try {
33
+ if (refreshToken) {
34
+ await this.tokenFacade.revokeToken(refreshToken);
35
+ }
36
+ }
37
+ catch (revokeError) {
38
+ this.logger.warn('Failed to revoke refresh token during user-context recovery', {
39
+ error: formatError(revokeError),
40
+ });
41
+ }
42
+ clearCookie(res, CORE_REFRESH_TOKEN_COOKIE, req);
43
+ clearBetterAuthCookies(res, req);
44
+ }
45
+ /**
46
+ * Completes auth flow using Identity refresh token (platform fast-path).
47
+ */
48
+ async completeWithIdentityRefreshToken(refreshToken, params, req, res) {
49
+ const state = extractState(req);
50
+ if (!state) {
51
+ this.logger.warn('Missing or mismatched state for identity refresh flow');
52
+ return null;
53
+ }
54
+ try {
55
+ const auth = await this.tokenFacade.refreshToken(refreshToken);
56
+ if (auth.refreshToken && auth.refreshTokenExpiresIn !== undefined) {
57
+ this.tokenFacade.setTokenToCookie(res, req, auth.refreshToken, auth.refreshTokenExpiresIn);
58
+ }
59
+ const { user, account } = await this.userContextService.resolveFromToken(auth.accessToken);
60
+ const payload = buildUserInfoPayload({
61
+ state,
62
+ user,
63
+ account,
64
+ });
65
+ const result = await this.platformAuthFlowClient.completeAuthFlow(payload);
66
+ const redirectUrl = buildPlatformRedirectUrl({
67
+ baseUrl: this.idpOwoxConfig.idpConfig.platformSignInUrl,
68
+ code: result.code,
69
+ state,
70
+ params,
71
+ defaultSource: SOURCE.APP,
72
+ allowedRedirectOrigins: this.idpOwoxConfig.idpConfig.allowedRedirectOrigins,
73
+ });
74
+ if (!redirectUrl) {
75
+ this.logger.warn('Failed to build redirect URL after identity refresh');
76
+ }
77
+ return redirectUrl;
78
+ }
79
+ catch (error) {
80
+ if (isStateExpiredError(error)) {
81
+ clearAllAuthCookies(res, req);
82
+ return new URL(`/auth${ProtocolRoute.SIGN_IN}`, this.idpOwoxConfig.baseUrl);
83
+ }
84
+ if (error instanceof AuthenticationException) {
85
+ this.logger.warn('Failed to resolve user from access token, redirecting to sign-in', {
86
+ error: formatError(error),
87
+ });
88
+ await this.revokeRefreshTokenAndClearCookies(refreshToken, req, res);
89
+ return new URL(`/auth${ProtocolRoute.SIGN_IN}`, this.idpOwoxConfig.baseUrl);
90
+ }
91
+ this.logger.warn('Platform fast-path failed, will fallback to UI', {
92
+ error: formatError(error),
93
+ });
94
+ return null;
95
+ }
96
+ }
97
+ /**
98
+ * Completes auth flow using Better Auth session token received from handler response.
99
+ */
100
+ async completeWithSocialSessionToken(sessionToken, params, req, res) {
101
+ const state = extractStateFromCookie(req);
102
+ if (!state) {
103
+ this.logger.warn('Missing or mismatched state for social login flow');
104
+ clearAllAuthCookies(res, req);
105
+ return new URL(`/auth${ProtocolRoute.SIGN_IN}`, this.idpOwoxConfig.baseUrl);
106
+ }
107
+ try {
108
+ const { code, payload } = await this.betterAuthSessionService.completeAuthFlowWithSessionToken(sessionToken, state);
109
+ const finalState = payload.state || state;
110
+ const redirectUrl = buildPlatformRedirectUrl({
111
+ baseUrl: this.idpOwoxConfig.idpConfig.platformSignInUrl,
112
+ code,
113
+ state: finalState || '',
114
+ params,
115
+ defaultSource: SOURCE.APP,
116
+ allowedRedirectOrigins: this.idpOwoxConfig.idpConfig.allowedRedirectOrigins,
117
+ });
118
+ if (redirectUrl) {
119
+ clearAllAuthCookies(res, req);
120
+ return redirectUrl;
121
+ }
122
+ }
123
+ catch (error) {
124
+ if (isStateExpiredError(error)) {
125
+ clearAllAuthCookies(res, req);
126
+ return new URL(`/auth${ProtocolRoute.SIGN_IN}`, this.idpOwoxConfig.baseUrl);
127
+ }
128
+ this.logger.warn('Auto-complete auth flow on callback failed', { error: formatError(error) });
129
+ clearAllAuthCookies(res, req);
130
+ return null;
131
+ }
132
+ return null;
133
+ }
134
+ }
@@ -0,0 +1,16 @@
1
+ import type { IdentityOwoxClient } from '../../client/IdentityOwoxClient.js';
2
+ import type { AuthFlowRequest } from '../../client/dto/authFlowDto.js';
3
+ export type UserInfoPayload = AuthFlowRequest;
4
+ /**
5
+ * Client wrapper for Platform auth flow completion with logging.
6
+ * Delegates HTTP communication to IdentityOwoxClient.
7
+ */
8
+ export declare class PlatformAuthFlowClient {
9
+ private readonly identityClient;
10
+ constructor(identityClient: IdentityOwoxClient);
11
+ /** Exchanges user info for a one-time authorization code. */
12
+ completeAuthFlow(payload: UserInfoPayload): Promise<{
13
+ code: string;
14
+ }>;
15
+ }
16
+ //# sourceMappingURL=platform-auth-flow-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-auth-flow-client.d.ts","sourceRoot":"","sources":["../../../src/services/auth/platform-auth-flow-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAoB,MAAM,iCAAiC,CAAC;AAGzF,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC;AAE9C;;;GAGG;AACH,qBAAa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,kBAAkB;IAE/D,6DAA6D;IACvD,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAsB5E"}
@@ -0,0 +1,32 @@
1
+ import { logger } from '../../core/logger.js';
2
+ /**
3
+ * Client wrapper for Platform auth flow completion with logging.
4
+ * Delegates HTTP communication to IdentityOwoxClient.
5
+ */
6
+ export class PlatformAuthFlowClient {
7
+ identityClient;
8
+ constructor(identityClient) {
9
+ this.identityClient = identityClient;
10
+ }
11
+ /** Exchanges user info for a one-time authorization code. */
12
+ async completeAuthFlow(payload) {
13
+ logger.info('Completing auth flow', {
14
+ hasState: Boolean(payload.state),
15
+ signinProvider: payload.userInfo.signinProvider,
16
+ userId: payload.userInfo.uid,
17
+ });
18
+ try {
19
+ // Delegate HTTP communication to the client layer
20
+ const response = await this.identityClient.completeAuthFlow(payload);
21
+ logger.info('Auth flow completed successfully', {
22
+ hasCode: Boolean(response.code),
23
+ });
24
+ return { code: response.code };
25
+ }
26
+ catch (error) {
27
+ // Log error with context for troubleshooting
28
+ logger.error('Failed to complete auth flow', {}, error);
29
+ throw error;
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,25 @@
1
+ import { Payload } from '@owox/idp-protocol';
2
+ import ms from 'ms';
3
+ import { IdentityOwoxClient } from '../../client/index.js';
4
+ export interface TokenServiceConfig {
5
+ algorithm: string;
6
+ clockTolerance: ms.StringValue | number;
7
+ issuer: string;
8
+ jwtKeyCacheTtl: ms.StringValue;
9
+ }
10
+ /**
11
+ * Validates and parses JWT access tokens using JWKS cache.
12
+ */
13
+ export declare class TokenService {
14
+ private readonly client;
15
+ private readonly config;
16
+ private readonly jwksCache;
17
+ constructor(client: IdentityOwoxClient, config: TokenServiceConfig);
18
+ normalizeToken(authorization: string): string;
19
+ parse(token: string): Promise<Payload | null>;
20
+ verify(token: string): Promise<Payload | null>;
21
+ formatError(error: unknown): string;
22
+ private fetchJwks;
23
+ private verifyJwt;
24
+ }
25
+ //# sourceMappingURL=token-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-service.d.ts","sourceRoot":"","sources":["../../../src/services/core/token-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAM3D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,EAAE,CAAC,WAAW,GAAG,MAAM,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,EAAE,CAAC,WAAW,CAAC;CAChC;AAED;;GAEG;AACH,qBAAa,YAAY;IAIrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAGR,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,kBAAkB;IAK7C,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAIvC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAU7C,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAIpD,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;YAIrB,SAAS;YAKT,SAAS;CAsBxB"}
@@ -0,0 +1,56 @@
1
+ import { decodeProtectedHeader } from 'jose';
2
+ import ms from 'ms';
3
+ import { makeJwksCache } from '../../jwt/jwksCache.js';
4
+ import { verify } from '../../jwt/verifyJwt.js';
5
+ import { toPayload } from '../../mappers/client-payload-mapper.js';
6
+ import { formatError } from '../../utils/string-utils.js';
7
+ /**
8
+ * Validates and parses JWT access tokens using JWKS cache.
9
+ */
10
+ export class TokenService {
11
+ client;
12
+ config;
13
+ jwksCache;
14
+ constructor(client, config) {
15
+ this.client = client;
16
+ this.config = config;
17
+ this.jwksCache = makeJwksCache(this.fetchJwks.bind(this), 'OWOX_JWKS');
18
+ }
19
+ normalizeToken(authorization) {
20
+ return authorization.replace(/^Bearer\s+/i, '').trim();
21
+ }
22
+ async parse(token) {
23
+ try {
24
+ const normalized = this.normalizeToken(token);
25
+ const { payload } = await this.verifyJwt(normalized);
26
+ return toPayload(payload);
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ async verify(token) {
33
+ return this.parse(token);
34
+ }
35
+ formatError(error) {
36
+ return formatError(error);
37
+ }
38
+ async fetchJwks() {
39
+ const resp = await this.client.getJwks();
40
+ return { keys: resp.keys };
41
+ }
42
+ async verifyJwt(token) {
43
+ const { alg } = decodeProtectedHeader(token);
44
+ if (alg && alg !== this.config.algorithm) {
45
+ throw new Error(`Unsupported JWT alg: ${alg}`);
46
+ }
47
+ const clockToleranceSeconds = typeof this.config.clockTolerance === 'string'
48
+ ? ms(this.config.clockTolerance) / 1000
49
+ : this.config.clockTolerance;
50
+ return verify(token, async () => (await this.jwksCache.get(ms(this.config.jwtKeyCacheTtl))).keyResolver, async () => (await this.jwksCache.refresh(ms(this.config.jwtKeyCacheTtl))).keyResolver, {
51
+ algorithm: this.config.algorithm,
52
+ clockTolerance: clockToleranceSeconds,
53
+ issuer: this.config.issuer,
54
+ });
55
+ }
56
+ }