@venturekit/auth 0.0.1 → 0.0.2

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 (54) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +5 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/migrations/vk_auth_003_role_scopes.sql +43 -0
  6. package/dist/roles/index.d.ts +5 -1
  7. package/dist/roles/index.d.ts.map +1 -1
  8. package/dist/roles/index.js +4 -1
  9. package/dist/roles/index.js.map +1 -1
  10. package/dist/roles/role-scopes.d.ts +92 -0
  11. package/dist/roles/role-scopes.d.ts.map +1 -0
  12. package/dist/roles/role-scopes.js +122 -0
  13. package/dist/roles/role-scopes.js.map +1 -0
  14. package/dist/server/cookies.d.ts +77 -6
  15. package/dist/server/cookies.d.ts.map +1 -1
  16. package/dist/server/cookies.js +55 -13
  17. package/dist/server/cookies.js.map +1 -1
  18. package/dist/server/federated-routes.d.ts +29 -22
  19. package/dist/server/federated-routes.d.ts.map +1 -1
  20. package/dist/server/federated-routes.js +31 -4
  21. package/dist/server/federated-routes.js.map +1 -1
  22. package/dist/server/federated.d.ts.map +1 -1
  23. package/dist/server/federated.js +7 -11
  24. package/dist/server/federated.js.map +1 -1
  25. package/dist/server/handoff-routes.d.ts +130 -0
  26. package/dist/server/handoff-routes.d.ts.map +1 -0
  27. package/dist/server/handoff-routes.js +178 -0
  28. package/dist/server/handoff-routes.js.map +1 -0
  29. package/dist/server/handoff.d.ts +112 -0
  30. package/dist/server/handoff.d.ts.map +1 -0
  31. package/dist/server/handoff.js +102 -0
  32. package/dist/server/handoff.js.map +1 -0
  33. package/dist/server/index.d.ts +10 -3
  34. package/dist/server/index.d.ts.map +1 -1
  35. package/dist/server/index.js +8 -2
  36. package/dist/server/index.js.map +1 -1
  37. package/dist/server/passwordless.d.ts +68 -0
  38. package/dist/server/passwordless.d.ts.map +1 -0
  39. package/dist/server/passwordless.js +136 -0
  40. package/dist/server/passwordless.js.map +1 -0
  41. package/dist/server/revoke.d.ts +10 -0
  42. package/dist/server/revoke.d.ts.map +1 -1
  43. package/dist/server/revoke.js +19 -1
  44. package/dist/server/revoke.js.map +1 -1
  45. package/dist/server/store/postgres.d.ts +35 -0
  46. package/dist/server/store/postgres.d.ts.map +1 -0
  47. package/dist/server/store/postgres.js +88 -0
  48. package/dist/server/store/postgres.js.map +1 -0
  49. package/dist/server/token-utils.d.ts +12 -2
  50. package/dist/server/token-utils.d.ts.map +1 -1
  51. package/dist/server/token-utils.js +9 -4
  52. package/dist/server/token-utils.js.map +1 -1
  53. package/package.json +13 -4
  54. package/src/migrations/vk_auth_003_role_scopes.sql +43 -0
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Cross-domain session handoff — core primitives.
3
+ *
4
+ * **Why this exists.** Browser cookies cannot span registrable domains:
5
+ * a session on `app.platform.com` can never be read by `tenant.io`, no
6
+ * matter what `Domain=` attribute it carries. Multi-tenant products
7
+ * with white-label custom domains therefore need an SSO-style handoff
8
+ * to "move" a session between hosts: the host WITH a session mints a
9
+ * short-lived, single-use **handoff code** bound to the target host;
10
+ * the target host redeems it server-side and mints its own first-party
11
+ * cookies. The user's refresh token travels server-to-server through
12
+ * the app's {@link HandoffStore} — only the opaque code ever appears
13
+ * in a URL.
14
+ *
15
+ * **Security properties**
16
+ * - Codes are 256-bit `crypto.randomBytes` values — unguessable.
17
+ * - The store is keyed by the **SHA-256 hash** of the code, so a
18
+ * leaked store (DB dump, logs) cannot be replayed into sessions.
19
+ * - Codes are single-use: {@link HandoffStore.take} must delete
20
+ * atomically (e.g. SQL `DELETE … RETURNING`).
21
+ * - Codes expire after {@link DEFAULT_HANDOFF_TTL_SECONDS}; expiry is
22
+ * enforced BOTH by the store's TTL mechanism and re-checked here on
23
+ * redeem, so a lagging store cleanup can't extend the window.
24
+ * - Codes are bound to the target host at issue time; redeeming on
25
+ * any other host fails — and a wrong-host attempt BURNS the code,
26
+ * so it cannot be probed and then replayed on the right host.
27
+ * Combined with the route factory's `authorize` hook this
28
+ * guarantees a session can only ever materialize on hosts the app
29
+ * explicitly approved for THIS user.
30
+ * - The `complete` redirects carry `Cache-Control: no-store` and
31
+ * `Referrer-Policy: no-referrer` so the code-bearing URL never
32
+ * sits in a shared cache and never leaks via `Referer`.
33
+ *
34
+ * **Residual risks — know what this does NOT protect against**
35
+ * - *Login CSRF*: like every URL-based SSO handoff (OAuth code flow
36
+ * included), an attacker can mint a code for THEIR OWN session and
37
+ * lure a victim into opening the complete URL, logging the victim
38
+ * in as the attacker on that host. The 60s single-use window and
39
+ * the membership-gated `authorize` hook narrow this to hosts the
40
+ * ATTACKER belongs to; apps for which this matters should show the
41
+ * signed-in identity prominently post-handoff.
42
+ * - *Store contents*: payloads hold live refresh tokens. The hashed
43
+ * key prevents lookup-by-code, rows die in ≤60s, but a hostile DBA
44
+ * window exists — encrypt payloads at rest if that is in scope.
45
+ *
46
+ * The route-level flow lives in `handoff-routes.ts`
47
+ * ({@link createSessionHandoffRoutes}); apps supply the storage
48
+ * (Postgres / DynamoDB / Redis — anything with atomic take).
49
+ */
50
+ /** Default lifetime of a handoff code: one browser redirect, not more. */
51
+ export declare const DEFAULT_HANDOFF_TTL_SECONDS = 60;
52
+ /**
53
+ * What the issuing host stashes for the target host to redeem.
54
+ *
55
+ * Contains the user's **refresh token** — treat stored payloads as
56
+ * secrets (the code-hash key already prevents lookup-by-code, and rows
57
+ * are deleted on redeem / expiry, but encrypt at rest if your store's
58
+ * threat model calls for it).
59
+ */
60
+ export interface HandoffPayload {
61
+ /** Cognito subject of the user the session belongs to. */
62
+ sub: string;
63
+ /** The session's refresh token — used by the target host to mint fresh tokens. */
64
+ refreshToken: string;
65
+ /** Host (including port, lowercased) the code was issued FOR. */
66
+ targetHost: string;
67
+ /** Epoch millis after which the code is dead even if the store still has it. */
68
+ expiresAt: number;
69
+ }
70
+ /**
71
+ * Storage the app provides for in-flight handoff codes.
72
+ *
73
+ * Keys are code **hashes** (see module docs). Implementations must make
74
+ * `take` atomic — two concurrent redeems of the same code must never
75
+ * both succeed:
76
+ *
77
+ * ```sql
78
+ * -- Postgres example
79
+ * DELETE FROM auth_handoff_codes WHERE code_hash = $1 RETURNING payload;
80
+ * ```
81
+ */
82
+ export interface HandoffStore {
83
+ /** Persist a payload under `codeHash`, expiring after `ttlSeconds`. */
84
+ put(codeHash: string, payload: HandoffPayload, ttlSeconds: number): Promise<void>;
85
+ /** Atomically fetch AND delete. Returns null when absent (or already taken). */
86
+ take(codeHash: string): Promise<HandoffPayload | null>;
87
+ }
88
+ /** Generate an unguessable handoff code (256-bit, base64url). */
89
+ export declare function generateHandoffCode(): string;
90
+ /** Hash a handoff code for use as a store key. */
91
+ export declare function hashHandoffCode(code: string): string;
92
+ /**
93
+ * Issue a handoff code for `targetHost`.
94
+ *
95
+ * @returns the RAW code — put it in the redirect URL. Only its hash
96
+ * touches the store.
97
+ */
98
+ export declare function issueHandoffCode(store: HandoffStore, input: {
99
+ sub: string;
100
+ refreshToken: string;
101
+ targetHost: string;
102
+ }, ttlSeconds?: number): Promise<string>;
103
+ /**
104
+ * Redeem a handoff code on `currentHost`.
105
+ *
106
+ * Returns the payload when the code exists, hasn't expired, and was
107
+ * issued for exactly this host — null otherwise. The code is consumed
108
+ * either way (single-use: a failed redeem must burn it too, so an
109
+ * attacker can't probe).
110
+ */
111
+ export declare function redeemHandoffCode(store: HandoffStore, code: string, currentHost: string): Promise<HandoffPayload | null>;
112
+ //# sourceMappingURL=handoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../../src/server/handoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAIH,0EAA0E;AAC1E,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAE9C;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,gFAAgF;IAChF,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACxD;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAOD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EAChE,UAAU,GAAE,MAAoC,GAC/C,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOhC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Cross-domain session handoff — core primitives.
3
+ *
4
+ * **Why this exists.** Browser cookies cannot span registrable domains:
5
+ * a session on `app.platform.com` can never be read by `tenant.io`, no
6
+ * matter what `Domain=` attribute it carries. Multi-tenant products
7
+ * with white-label custom domains therefore need an SSO-style handoff
8
+ * to "move" a session between hosts: the host WITH a session mints a
9
+ * short-lived, single-use **handoff code** bound to the target host;
10
+ * the target host redeems it server-side and mints its own first-party
11
+ * cookies. The user's refresh token travels server-to-server through
12
+ * the app's {@link HandoffStore} — only the opaque code ever appears
13
+ * in a URL.
14
+ *
15
+ * **Security properties**
16
+ * - Codes are 256-bit `crypto.randomBytes` values — unguessable.
17
+ * - The store is keyed by the **SHA-256 hash** of the code, so a
18
+ * leaked store (DB dump, logs) cannot be replayed into sessions.
19
+ * - Codes are single-use: {@link HandoffStore.take} must delete
20
+ * atomically (e.g. SQL `DELETE … RETURNING`).
21
+ * - Codes expire after {@link DEFAULT_HANDOFF_TTL_SECONDS}; expiry is
22
+ * enforced BOTH by the store's TTL mechanism and re-checked here on
23
+ * redeem, so a lagging store cleanup can't extend the window.
24
+ * - Codes are bound to the target host at issue time; redeeming on
25
+ * any other host fails — and a wrong-host attempt BURNS the code,
26
+ * so it cannot be probed and then replayed on the right host.
27
+ * Combined with the route factory's `authorize` hook this
28
+ * guarantees a session can only ever materialize on hosts the app
29
+ * explicitly approved for THIS user.
30
+ * - The `complete` redirects carry `Cache-Control: no-store` and
31
+ * `Referrer-Policy: no-referrer` so the code-bearing URL never
32
+ * sits in a shared cache and never leaks via `Referer`.
33
+ *
34
+ * **Residual risks — know what this does NOT protect against**
35
+ * - *Login CSRF*: like every URL-based SSO handoff (OAuth code flow
36
+ * included), an attacker can mint a code for THEIR OWN session and
37
+ * lure a victim into opening the complete URL, logging the victim
38
+ * in as the attacker on that host. The 60s single-use window and
39
+ * the membership-gated `authorize` hook narrow this to hosts the
40
+ * ATTACKER belongs to; apps for which this matters should show the
41
+ * signed-in identity prominently post-handoff.
42
+ * - *Store contents*: payloads hold live refresh tokens. The hashed
43
+ * key prevents lookup-by-code, rows die in ≤60s, but a hostile DBA
44
+ * window exists — encrypt payloads at rest if that is in scope.
45
+ *
46
+ * The route-level flow lives in `handoff-routes.ts`
47
+ * ({@link createSessionHandoffRoutes}); apps supply the storage
48
+ * (Postgres / DynamoDB / Redis — anything with atomic take).
49
+ */
50
+ import { createHash, randomBytes } from 'node:crypto';
51
+ /** Default lifetime of a handoff code: one browser redirect, not more. */
52
+ export const DEFAULT_HANDOFF_TTL_SECONDS = 60;
53
+ /** Generate an unguessable handoff code (256-bit, base64url). */
54
+ export function generateHandoffCode() {
55
+ return randomBytes(32).toString('base64url');
56
+ }
57
+ /** Hash a handoff code for use as a store key. */
58
+ export function hashHandoffCode(code) {
59
+ return createHash('sha256').update(code).digest('base64url');
60
+ }
61
+ /** Lowercase a host for comparison. Ports are significant (dev hosts). */
62
+ function normalizeHost(host) {
63
+ return host.trim().toLowerCase();
64
+ }
65
+ /**
66
+ * Issue a handoff code for `targetHost`.
67
+ *
68
+ * @returns the RAW code — put it in the redirect URL. Only its hash
69
+ * touches the store.
70
+ */
71
+ export async function issueHandoffCode(store, input, ttlSeconds = DEFAULT_HANDOFF_TTL_SECONDS) {
72
+ const code = generateHandoffCode();
73
+ const payload = {
74
+ sub: input.sub,
75
+ refreshToken: input.refreshToken,
76
+ targetHost: normalizeHost(input.targetHost),
77
+ expiresAt: Date.now() + ttlSeconds * 1000,
78
+ };
79
+ await store.put(hashHandoffCode(code), payload, ttlSeconds);
80
+ return code;
81
+ }
82
+ /**
83
+ * Redeem a handoff code on `currentHost`.
84
+ *
85
+ * Returns the payload when the code exists, hasn't expired, and was
86
+ * issued for exactly this host — null otherwise. The code is consumed
87
+ * either way (single-use: a failed redeem must burn it too, so an
88
+ * attacker can't probe).
89
+ */
90
+ export async function redeemHandoffCode(store, code, currentHost) {
91
+ if (!code)
92
+ return null;
93
+ const payload = await store.take(hashHandoffCode(code));
94
+ if (!payload)
95
+ return null;
96
+ if (Date.now() > payload.expiresAt)
97
+ return null;
98
+ if (payload.targetHost !== normalizeHost(currentHost))
99
+ return null;
100
+ return payload;
101
+ }
102
+ //# sourceMappingURL=handoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.js","sourceRoot":"","sources":["../../src/server/handoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAwC9C,iEAAiE;AACjE,MAAM,UAAU,mBAAmB;IACjC,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC/C,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAC/D,CAAC;AAED,0EAA0E;AAC1E,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAmB,EACnB,KAAgE,EAChE,aAAqB,2BAA2B;IAEhD,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAC;IACnC,MAAM,OAAO,GAAmB;QAC9B,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC;QAC3C,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;KAC1C,CAAC;IACF,MAAM,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAmB,EACnB,IAAY,EACZ,WAAmB;IAEnB,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;IACxD,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAChD,IAAI,OAAO,CAAC,UAAU,KAAK,aAAa,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IACnE,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -34,19 +34,26 @@ export type { AdminInviteUserInput, AdminInviteUserResult, AdminUpdateAttributes
34
34
  export { adminInviteUser, adminUpdateUserAttributes, adminDisableUser, adminEnableUser, adminDeleteUser, } from './admin-users.js';
35
35
  export type { RefreshResult } from './refresh.js';
36
36
  export { refreshSession } from './refresh.js';
37
- export { revokeRefreshToken } from './revoke.js';
37
+ export { revokeRefreshToken, globalSignOut } from './revoke.js';
38
+ export type { EnsureUserForVerifiedEmailInput, EnsureUserForVerifiedEmailResult, } from './passwordless.js';
39
+ export { ensureUserForVerifiedEmail, mintSessionForVerifiedEmail, } from './passwordless.js';
38
40
  export type { ChangePasswordInput } from './change-password.js';
39
41
  export { changePassword } from './change-password.js';
40
42
  export type { ForgotPasswordInput, ForgotPasswordResult, ConfirmForgotPasswordInput, CodeDeliveryDetails, } from './forgot-password.js';
41
43
  export { forgotPassword, confirmForgotPassword } from './forgot-password.js';
42
44
  export type { VerifyOptions } from './verify.js';
43
45
  export { verifyAndDecode } from './verify.js';
44
- export type { SessionTokens, CookieOptions, OAuthStateCookieOptions, } from './cookies.js';
45
- export { ID_TOKEN_COOKIE, ACCESS_TOKEN_COOKIE, REFRESH_TOKEN_COOKIE, buildSessionCookies, buildClearSessionCookies, readCookieFromHeader, buildOAuthStateCookie, clearOAuthStateCookie, oauthStateCookieName, } from './cookies.js';
46
+ export { decodeJwtClaims } from './token-utils.js';
47
+ export type { SessionTokens, CookieOptions, CookieDomainOptions, OAuthStateCookieOptions, } from './cookies.js';
48
+ export { ID_TOKEN_COOKIE, ACCESS_TOKEN_COOKIE, REFRESH_TOKEN_COOKIE, buildSessionCookies, buildClearSessionCookies, readCookieFromHeader, buildOAuthStateCookie, clearOAuthStateCookie, oauthStateCookieName, resolveCookieDomain, } from './cookies.js';
46
49
  export type { CookieAuthMiddlewareOptions } from './middleware.js';
47
50
  export { cookieAuthMiddleware, extractToken, defaultScopeMapper } from './middleware.js';
48
51
  export type { FederatedAuthRoutes, FederatedAuthRoutesOptions, FederatedCallbackBody, FederatedCallbackResult, FederatedOnSignInArgs, FederatedOnSignInResult, FederatedStartBody, } from './federated-routes.js';
49
52
  export { createFederatedAuthRoutes } from './federated-routes.js';
53
+ export type { HandoffPayload, HandoffStore } from './handoff.js';
54
+ export { DEFAULT_HANDOFF_TTL_SECONDS, generateHandoffCode, hashHandoffCode, issueHandoffCode, redeemHandoffCode, } from './handoff.js';
55
+ export type { HandoffAuthorizeArgs, HandoffStartBody, SessionHandoffRoutes, SessionHandoffRoutesOptions, } from './handoff-routes.js';
56
+ export { createSessionHandoffRoutes, DEFAULT_HANDOFF_COMPLETE_PATH, } from './handoff-routes.js';
50
57
  export type { FederatedProvider, FederatedProfile, FederatedProviderCredentials, SignInAsFederatedUserInput, BuildAuthorizeUrlInput, ExchangeAuthorizationCodeInput, } from './federated.js';
51
58
  export { loadFederatedProviderCredentials, generateOAuthState, verifyOAuthState, buildAuthorizeUrl, exchangeAuthorizationCode, signInAsFederatedUser, } from './federated.js';
52
59
  export type { VerificationChannel, VerificationCodeStore, VerificationCodeRecord, RequestVerificationCodeInput, RequestVerificationCodeResult, VerifyVerificationCodeInput, } from './verification.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -28,13 +28,19 @@ export { signInWithPasswordOrChallenge, respondToNewPasswordChallenge, } from '.
28
28
  export { signUpUser } from './sign-up.js';
29
29
  export { adminInviteUser, adminUpdateUserAttributes, adminDisableUser, adminEnableUser, adminDeleteUser, } from './admin-users.js';
30
30
  export { refreshSession } from './refresh.js';
31
- export { revokeRefreshToken } from './revoke.js';
31
+ export { revokeRefreshToken, globalSignOut } from './revoke.js';
32
+ export { ensureUserForVerifiedEmail, mintSessionForVerifiedEmail, } from './passwordless.js';
32
33
  export { changePassword } from './change-password.js';
33
34
  export { forgotPassword, confirmForgotPassword } from './forgot-password.js';
34
35
  export { verifyAndDecode } from './verify.js';
35
- export { ID_TOKEN_COOKIE, ACCESS_TOKEN_COOKIE, REFRESH_TOKEN_COOKIE, buildSessionCookies, buildClearSessionCookies, readCookieFromHeader, buildOAuthStateCookie, clearOAuthStateCookie, oauthStateCookieName, } from './cookies.js';
36
+ // Unverified claim extraction ONLY for tokens received directly
37
+ // from the provider (e.g. reading profile claims right after sign-in).
38
+ export { decodeJwtClaims } from './token-utils.js';
39
+ export { ID_TOKEN_COOKIE, ACCESS_TOKEN_COOKIE, REFRESH_TOKEN_COOKIE, buildSessionCookies, buildClearSessionCookies, readCookieFromHeader, buildOAuthStateCookie, clearOAuthStateCookie, oauthStateCookieName, resolveCookieDomain, } from './cookies.js';
36
40
  export { cookieAuthMiddleware, extractToken, defaultScopeMapper } from './middleware.js';
37
41
  export { createFederatedAuthRoutes } from './federated-routes.js';
42
+ export { DEFAULT_HANDOFF_TTL_SECONDS, generateHandoffCode, hashHandoffCode, issueHandoffCode, redeemHandoffCode, } from './handoff.js';
43
+ export { createSessionHandoffRoutes, DEFAULT_HANDOFF_COMPLETE_PATH, } from './handoff-routes.js';
38
44
  export { loadFederatedProviderCredentials, generateOAuthState, verifyOAuthState, buildAuthorizeUrl, exchangeAuthorizationCode, signInAsFederatedUser, } from './federated.js';
39
45
  export { generateVerificationCode, hashVerificationCode, requestVerificationCode, verifyVerificationCode, createInMemoryVerificationCodeStore, } from './verification.js';
40
46
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOlD,OAAO,EACL,6BAA6B,EAC7B,6BAA6B,GAC9B,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAO1C,OAAO,EACL,eAAe,EACf,yBAAyB,EACzB,gBAAgB,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQtD,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAG7E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAO9C,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAWzF,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAUlE,OAAO,EACL,gCAAgC,EAChC,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAUxB,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,mCAAmC,GACpC,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOlD,OAAO,EACL,6BAA6B,EAC7B,6BAA6B,GAC9B,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAO1C,OAAO,EACL,eAAe,EACf,yBAAyB,EACzB,gBAAgB,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQhE,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQtD,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAG7E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,kEAAkE;AAClE,uEAAuE;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAQnD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAWzF,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAGlE,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAQtB,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,GAC9B,MAAM,qBAAqB,CAAC;AAU7B,OAAO,EACL,gCAAgC,EAChC,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AAUxB,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,mCAAmC,GACpC,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Server-verified (passwordless) identity flows.
3
+ *
4
+ * For UXes where the APP proves address ownership out-of-band — magic
5
+ * links, OAuth/OIDC callbacks, emailed one-time codes — and Cognito is
6
+ * only the identity/token backend, never the credential UI:
7
+ *
8
+ * 1. {@link ensureUserForVerifiedEmail} — idempotently create the
9
+ * Cognito user (invite email suppressed, `email_verified=true`)
10
+ * or fetch the existing one; the returned `sub` doubles as the
11
+ * app's `users.id`.
12
+ * 2. {@link mintSessionForVerifiedEmail} — rotate the user's
13
+ * password to a throwaway strong secret (`AdminSetUserPassword`,
14
+ * permanent) and immediately sign in via
15
+ * `InitiateAuth(USER_PASSWORD_AUTH)`. The password is discarded;
16
+ * only the tokens leave the function.
17
+ *
18
+ * Requirements:
19
+ * - the app client must allow `ALLOW_USER_PASSWORD_AUTH`;
20
+ * - the caller's IAM role needs the `cognito-idp:Admin*` actions
21
+ * used below (VentureKit's auth intent grants them to the API
22
+ * Lambdas).
23
+ *
24
+ * Security notes:
25
+ * - the rotated password never leaves the server and satisfies the
26
+ * default "strong" policy (length + upper/lower/digit/symbol);
27
+ * - replays are benign: re-minting just issues another valid token
28
+ * set for the same identity — revoke on sign-out;
29
+ * - concurrent mints race harmlessly (last rotation wins, every
30
+ * token set issued stays valid until expiry/revocation).
31
+ */
32
+ import type { AuthServerConfig } from './config.js';
33
+ import { type SignInResult } from './tokens.js';
34
+ export interface EnsureUserForVerifiedEmailInput {
35
+ /** Address the app has already proven ownership of. */
36
+ email: string;
37
+ /** Optional standard attributes copied onto the Cognito record. */
38
+ firstName?: string;
39
+ lastName?: string;
40
+ /**
41
+ * Additional attributes (e.g. `{ 'custom:tenantRoles': '…' }`).
42
+ * Applied on create AND refreshed on subsequent calls.
43
+ */
44
+ attributes?: Record<string, string>;
45
+ }
46
+ export interface EnsureUserForVerifiedEmailResult {
47
+ /** Cognito `sub` (UUID) — commonly reused as the app's user id. */
48
+ sub: string;
49
+ /** True when this call created the Cognito user. */
50
+ created: boolean;
51
+ }
52
+ /**
53
+ * Idempotently ensure a Cognito user exists for a server-verified
54
+ * email. New users are auto-confirmed with `email_verified=true` and
55
+ * the invite email suppressed — the app owns the UX. On subsequent
56
+ * calls the profile attributes are refreshed best-effort.
57
+ */
58
+ export declare function ensureUserForVerifiedEmail(input: EnsureUserForVerifiedEmailInput, config?: AuthServerConfig): Promise<EnsureUserForVerifiedEmailResult>;
59
+ /**
60
+ * Mint a full token set (id + access + refresh) for a user whose
61
+ * email the app just verified: rotate the password server-side, sign
62
+ * in with it, discard it.
63
+ *
64
+ * Throws {@link AuthError} when the rotation or sign-in fails (e.g.
65
+ * `USER_PASSWORD_AUTH` not enabled on the app client).
66
+ */
67
+ export declare function mintSessionForVerifiedEmail(email: string, config?: AuthServerConfig): Promise<SignInResult>;
68
+ //# sourceMappingURL=passwordless.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passwordless.d.ts","sourceRoot":"","sources":["../../src/server/passwordless.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAaH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAWrE,MAAM,WAAW,+BAA+B;IAC9C,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,gCAAgC;IAC/C,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,+BAA+B,EACtC,MAAM,GAAE,gBAAyC,GAChD,OAAO,CAAC,gCAAgC,CAAC,CAgE3C;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,gBAAyC,GAChD,OAAO,CAAC,YAAY,CAAC,CAyBvB"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Server-verified (passwordless) identity flows.
3
+ *
4
+ * For UXes where the APP proves address ownership out-of-band — magic
5
+ * links, OAuth/OIDC callbacks, emailed one-time codes — and Cognito is
6
+ * only the identity/token backend, never the credential UI:
7
+ *
8
+ * 1. {@link ensureUserForVerifiedEmail} — idempotently create the
9
+ * Cognito user (invite email suppressed, `email_verified=true`)
10
+ * or fetch the existing one; the returned `sub` doubles as the
11
+ * app's `users.id`.
12
+ * 2. {@link mintSessionForVerifiedEmail} — rotate the user's
13
+ * password to a throwaway strong secret (`AdminSetUserPassword`,
14
+ * permanent) and immediately sign in via
15
+ * `InitiateAuth(USER_PASSWORD_AUTH)`. The password is discarded;
16
+ * only the tokens leave the function.
17
+ *
18
+ * Requirements:
19
+ * - the app client must allow `ALLOW_USER_PASSWORD_AUTH`;
20
+ * - the caller's IAM role needs the `cognito-idp:Admin*` actions
21
+ * used below (VentureKit's auth intent grants them to the API
22
+ * Lambdas).
23
+ *
24
+ * Security notes:
25
+ * - the rotated password never leaves the server and satisfies the
26
+ * default "strong" policy (length + upper/lower/digit/symbol);
27
+ * - replays are benign: re-minting just issues another valid token
28
+ * set for the same identity — revoke on sign-out;
29
+ * - concurrent mints race harmlessly (last rotation wins, every
30
+ * token set issued stays valid until expiry/revocation).
31
+ */
32
+ import { AdminCreateUserCommand, AdminGetUserCommand, AdminSetUserPasswordCommand, AdminUpdateUserAttributesCommand, InitiateAuthCommand, MessageActionType, UsernameExistsException, } from '@aws-sdk/client-cognito-identity-provider';
33
+ import { randomBytes } from 'node:crypto';
34
+ import { loadAuthServerConfig } from './config.js';
35
+ import { getCognitoClient } from './cognito-client.js';
36
+ import { AuthError, mapProviderError } from './errors.js';
37
+ import { extractSignInTokens } from './tokens.js';
38
+ /**
39
+ * Cryptographically random password satisfying Cognito's default
40
+ * "strong" policy: 40 base64url chars + `Aa1!` to guarantee the
41
+ * character-class mix. Internal — the value is never surfaced.
42
+ */
43
+ function generateRotatingPassword() {
44
+ return `${randomBytes(30).toString('base64url')}Aa1!`;
45
+ }
46
+ /**
47
+ * Idempotently ensure a Cognito user exists for a server-verified
48
+ * email. New users are auto-confirmed with `email_verified=true` and
49
+ * the invite email suppressed — the app owns the UX. On subsequent
50
+ * calls the profile attributes are refreshed best-effort.
51
+ */
52
+ export async function ensureUserForVerifiedEmail(input, config = loadAuthServerConfig()) {
53
+ const client = getCognitoClient(config.region, config.endpoint);
54
+ const email = input.email.trim().toLowerCase();
55
+ const attributes = [
56
+ { Name: 'email', Value: email },
57
+ { Name: 'email_verified', Value: 'true' },
58
+ ];
59
+ if (input.firstName)
60
+ attributes.push({ Name: 'given_name', Value: input.firstName });
61
+ if (input.lastName)
62
+ attributes.push({ Name: 'family_name', Value: input.lastName });
63
+ for (const [name, value] of Object.entries(input.attributes ?? {})) {
64
+ attributes.push({ Name: name, Value: value });
65
+ }
66
+ try {
67
+ const res = await client.send(new AdminCreateUserCommand({
68
+ UserPoolId: config.userPoolId,
69
+ Username: email,
70
+ UserAttributes: attributes,
71
+ MessageAction: MessageActionType.SUPPRESS,
72
+ }));
73
+ const sub = res.User?.Attributes?.find((a) => a.Name === 'sub')?.Value;
74
+ if (!sub) {
75
+ throw new AuthError('incomplete_auth_result', 'AdminCreateUser did not return a sub', 500);
76
+ }
77
+ return { sub, created: true };
78
+ }
79
+ catch (err) {
80
+ if (!(err instanceof UsernameExistsException)) {
81
+ throw err instanceof AuthError ? err : mapProviderError(err, 'sign_up_failed');
82
+ }
83
+ }
84
+ // Already present — fetch the sub and refresh mutable attributes.
85
+ const existing = await client.send(new AdminGetUserCommand({ UserPoolId: config.userPoolId, Username: email }));
86
+ const sub = existing.UserAttributes?.find((a) => a.Name === 'sub')?.Value;
87
+ if (!sub) {
88
+ throw new AuthError('incomplete_auth_result', 'AdminGetUser did not return a sub', 500);
89
+ }
90
+ const updates = attributes.filter((a) => a.Name !== 'email' && a.Name !== 'email_verified');
91
+ if (updates.length) {
92
+ try {
93
+ await client.send(new AdminUpdateUserAttributesCommand({
94
+ UserPoolId: config.userPoolId,
95
+ Username: email,
96
+ UserAttributes: updates,
97
+ }));
98
+ }
99
+ catch {
100
+ // Best-effort — stale profile attributes are not worth failing
101
+ // an authentication flow over.
102
+ }
103
+ }
104
+ return { sub, created: false };
105
+ }
106
+ /**
107
+ * Mint a full token set (id + access + refresh) for a user whose
108
+ * email the app just verified: rotate the password server-side, sign
109
+ * in with it, discard it.
110
+ *
111
+ * Throws {@link AuthError} when the rotation or sign-in fails (e.g.
112
+ * `USER_PASSWORD_AUTH` not enabled on the app client).
113
+ */
114
+ export async function mintSessionForVerifiedEmail(email, config = loadAuthServerConfig()) {
115
+ const client = getCognitoClient(config.region, config.endpoint);
116
+ const normalized = email.trim().toLowerCase();
117
+ const password = generateRotatingPassword();
118
+ try {
119
+ await client.send(new AdminSetUserPasswordCommand({
120
+ UserPoolId: config.userPoolId,
121
+ Username: normalized,
122
+ Password: password,
123
+ Permanent: true,
124
+ }));
125
+ const res = await client.send(new InitiateAuthCommand({
126
+ AuthFlow: 'USER_PASSWORD_AUTH',
127
+ ClientId: config.appClientId,
128
+ AuthParameters: { USERNAME: normalized, PASSWORD: password },
129
+ }));
130
+ return extractSignInTokens(res.AuthenticationResult);
131
+ }
132
+ catch (err) {
133
+ throw err instanceof AuthError ? err : mapProviderError(err, 'sign_in_failed');
134
+ }
135
+ }
136
+ //# sourceMappingURL=passwordless.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passwordless.js","sourceRoot":"","sources":["../../src/server/passwordless.ts"],"names":[],"mappings":"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"}
@@ -15,4 +15,14 @@ import type { AuthServerConfig } from './config.js';
15
15
  * the function never throws.
16
16
  */
17
17
  export declare function revokeRefreshToken(refreshToken: string, config?: AuthServerConfig): Promise<void>;
18
+ /**
19
+ * Invalidate EVERY outstanding refresh token for the caller via
20
+ * Cognito's `GlobalSignOut` (keyed by a valid access token, unlike
21
+ * {@link revokeRefreshToken} which revokes one refresh token). Already
22
+ * issued access tokens keep working until natural expiry.
23
+ *
24
+ * **Best-effort**, same contract as {@link revokeRefreshToken}: sign-out
25
+ * must never fail the user, so errors are logged and swallowed.
26
+ */
27
+ export declare function globalSignOut(accessToken: string, config?: AuthServerConfig): Promise<void>;
18
28
  //# sourceMappingURL=revoke.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"revoke.d.ts","sourceRoot":"","sources":["../../src/server/revoke.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,MAAM,GAAE,gBAAyC,GAChD,OAAO,CAAC,IAAI,CAAC,CAaf"}
1
+ {"version":3,"file":"revoke.d.ts","sourceRoot":"","sources":["../../src/server/revoke.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,MAAM,GAAE,gBAAyC,GAChD,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,MAAM,GAAE,gBAAyC,GAChD,OAAO,CAAC,IAAI,CAAC,CAQf"}
@@ -7,7 +7,7 @@
7
7
  * because the server-side revoke had a hiccup — the cookies clear
8
8
  * regardless.
9
9
  */
10
- import { RevokeTokenCommand } from '@aws-sdk/client-cognito-identity-provider';
10
+ import { GlobalSignOutCommand, RevokeTokenCommand, } from '@aws-sdk/client-cognito-identity-provider';
11
11
  import { loadAuthServerConfig } from './config.js';
12
12
  import { getCognitoClient } from './cognito-client.js';
13
13
  /**
@@ -28,4 +28,22 @@ export async function revokeRefreshToken(refreshToken, config = loadAuthServerCo
28
28
  console.warn('[@venturekit/auth/server] refresh-token revoke failed (ignored):', err);
29
29
  }
30
30
  }
31
+ /**
32
+ * Invalidate EVERY outstanding refresh token for the caller via
33
+ * Cognito's `GlobalSignOut` (keyed by a valid access token, unlike
34
+ * {@link revokeRefreshToken} which revokes one refresh token). Already
35
+ * issued access tokens keep working until natural expiry.
36
+ *
37
+ * **Best-effort**, same contract as {@link revokeRefreshToken}: sign-out
38
+ * must never fail the user, so errors are logged and swallowed.
39
+ */
40
+ export async function globalSignOut(accessToken, config = loadAuthServerConfig()) {
41
+ const client = getCognitoClient(config.region, config.endpoint);
42
+ try {
43
+ await client.send(new GlobalSignOutCommand({ AccessToken: accessToken }));
44
+ }
45
+ catch (err) {
46
+ console.warn('[@venturekit/auth/server] global sign-out failed (ignored):', err);
47
+ }
48
+ }
31
49
  //# sourceMappingURL=revoke.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"revoke.js","sourceRoot":"","sources":["../../src/server/revoke.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAE/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,YAAoB,EACpB,SAA2B,oBAAoB,EAAE;IAEjD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CACf,IAAI,kBAAkB,CAAC;YACrB,QAAQ,EAAE,MAAM,CAAC,WAAW;YAC5B,KAAK,EAAE,YAAY;SACpB,CAAC,CACH,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAEb,OAAO,CAAC,IAAI,CAAC,kEAAkE,EAAE,GAAG,CAAC,CAAC;IACxF,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"revoke.js","sourceRoot":"","sources":["../../src/server/revoke.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,YAAoB,EACpB,SAA2B,oBAAoB,EAAE;IAEjD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CACf,IAAI,kBAAkB,CAAC;YACrB,QAAQ,EAAE,MAAM,CAAC,WAAW;YAC5B,KAAK,EAAE,YAAY;SACpB,CAAC,CACH,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAEb,OAAO,CAAC,IAAI,CAAC,kEAAkE,EAAE,GAAG,CAAC,CAAC;IACxF,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,WAAmB,EACnB,SAA2B,oBAAoB,EAAE;IAEjD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAEb,OAAO,CAAC,IAAI,CAAC,6DAA6D,EAAE,GAAG,CAAC,CAAC;IACnF,CAAC;AACH,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @venturekit/auth — Postgres VerificationCodeStore
3
+ *
4
+ * Production {@link VerificationCodeStore} backing the OTP primitives
5
+ * ({@link requestVerificationCode} / {@link verifyVerificationCode}).
6
+ * Talks to the project's primary Postgres database via
7
+ * `@venturekit/data`'s `query()` — or any `Querier`, so the caller can
8
+ * enlist code writes in an already-open transaction (pass a
9
+ * `Transaction`'s `query`; the default is the global connection pool).
10
+ *
11
+ * The backing table `vk_verification_codes` is shipped by this package's
12
+ * `migrations/vk_auth_001_verification_codes.sql` and applied by the
13
+ * in-VPC migration runner `@venturekit/infra` provisions — so consumers
14
+ * get the table and this store from the same package.
15
+ *
16
+ * `@venturekit/data` is an OPTIONAL peer dependency: importing THIS
17
+ * module is what opts a project into the Postgres store, so apps on a
18
+ * different backend (DynamoDB, the in-memory dev store) never load it
19
+ * and `@venturekit/auth/server` stays storage-agnostic.
20
+ *
21
+ * `expires_at` crosses the store boundary as ms-epoch to satisfy
22
+ * {@link VerificationCodeRecord}'s numeric contract: `to_timestamp` on
23
+ * write, `EXTRACT(EPOCH …) * 1000` on read.
24
+ */
25
+ import { type Querier } from '@venturekit/data';
26
+ import type { VerificationCodeStore } from '../verification.js';
27
+ /**
28
+ * Build a Postgres-backed {@link VerificationCodeStore} bound to `q`.
29
+ *
30
+ * Pass a transaction's `query` (see `beginTransaction` /
31
+ * `withTransaction` in `@venturekit/data`) to make code writes
32
+ * participate in an open transaction; omit it to use the global pool.
33
+ */
34
+ export declare function createPostgresVerificationCodeStore(q?: Querier): VerificationCodeStore;
35
+ //# sourceMappingURL=postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../src/server/store/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAS,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAEV,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAwB5B;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CACjD,CAAC,GAAE,OAAe,GACjB,qBAAqB,CAgEvB"}