@seamless-auth/core 0.15.0 → 0.16.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 (77) hide show
  1. package/README.md +16 -2
  2. package/dist/applyResult.d.ts +11 -1
  3. package/dist/applyResult.d.ts.map +1 -1
  4. package/dist/applyResult.js +3 -1
  5. package/dist/applyResult.js.map +1 -1
  6. package/dist/getSeamlessUser.d.ts +14 -2
  7. package/dist/getSeamlessUser.d.ts.map +1 -1
  8. package/dist/getSeamlessUser.js +28 -10
  9. package/dist/getSeamlessUser.js.map +1 -1
  10. package/dist/guards.d.ts +39 -0
  11. package/dist/guards.d.ts.map +1 -1
  12. package/dist/guards.js +63 -0
  13. package/dist/guards.js.map +1 -1
  14. package/dist/handlers/finishLogin.d.ts +2 -0
  15. package/dist/handlers/finishLogin.d.ts.map +1 -1
  16. package/dist/handlers/finishLogin.js +4 -4
  17. package/dist/handlers/finishLogin.js.map +1 -1
  18. package/dist/handlers/login.d.ts +13 -5
  19. package/dist/handlers/login.d.ts.map +1 -1
  20. package/dist/handlers/login.js +6 -1
  21. package/dist/handlers/login.js.map +1 -1
  22. package/dist/handlers/oauthHandlers.d.ts +2 -0
  23. package/dist/handlers/oauthHandlers.d.ts.map +1 -1
  24. package/dist/handlers/oauthHandlers.js +4 -4
  25. package/dist/handlers/oauthHandlers.js.map +1 -1
  26. package/dist/handlers/pollMagicLinkConfirmationHandler.d.ts +2 -0
  27. package/dist/handlers/pollMagicLinkConfirmationHandler.d.ts.map +1 -1
  28. package/dist/handlers/pollMagicLinkConfirmationHandler.js +4 -4
  29. package/dist/handlers/pollMagicLinkConfirmationHandler.js.map +1 -1
  30. package/dist/handlers/refresh.d.ts +44 -0
  31. package/dist/handlers/refresh.d.ts.map +1 -0
  32. package/dist/handlers/refresh.js +70 -0
  33. package/dist/handlers/refresh.js.map +1 -0
  34. package/dist/handlers/register.d.ts +2 -0
  35. package/dist/handlers/register.d.ts.map +1 -1
  36. package/dist/handlers/register.js +3 -0
  37. package/dist/handlers/register.js.map +1 -1
  38. package/dist/handlers/switchOrganizationHandler.d.ts +2 -0
  39. package/dist/handlers/switchOrganizationHandler.d.ts.map +1 -1
  40. package/dist/handlers/switchOrganizationHandler.js +4 -4
  41. package/dist/handlers/switchOrganizationHandler.js.map +1 -1
  42. package/dist/handlers/verifyLoginOtpHandler.d.ts +2 -0
  43. package/dist/handlers/verifyLoginOtpHandler.d.ts.map +1 -1
  44. package/dist/handlers/verifyLoginOtpHandler.js +4 -4
  45. package/dist/handlers/verifyLoginOtpHandler.js.map +1 -1
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +3 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/jwks.d.ts +3 -0
  51. package/dist/jwks.d.ts.map +1 -0
  52. package/dist/jwks.js +15 -0
  53. package/dist/jwks.js.map +1 -0
  54. package/dist/proxyRequest.d.ts +9 -2
  55. package/dist/proxyRequest.d.ts.map +1 -1
  56. package/dist/proxyRequest.js +24 -14
  57. package/dist/proxyRequest.js.map +1 -1
  58. package/dist/refreshAccessToken.d.ts +19 -0
  59. package/dist/refreshAccessToken.d.ts.map +1 -1
  60. package/dist/refreshAccessToken.js +71 -21
  61. package/dist/refreshAccessToken.js.map +1 -1
  62. package/dist/transport.d.ts +20 -0
  63. package/dist/transport.d.ts.map +1 -0
  64. package/dist/transport.js +12 -0
  65. package/dist/transport.js.map +1 -0
  66. package/dist/upstreamSession.d.ts +19 -0
  67. package/dist/upstreamSession.d.ts.map +1 -1
  68. package/dist/upstreamSession.js +20 -0
  69. package/dist/upstreamSession.js.map +1 -1
  70. package/dist/verifyAccessToken.d.ts +30 -0
  71. package/dist/verifyAccessToken.d.ts.map +1 -0
  72. package/dist/verifyAccessToken.js +44 -0
  73. package/dist/verifyAccessToken.js.map +1 -0
  74. package/dist/verifySignedAuthResponse.d.ts.map +1 -1
  75. package/dist/verifySignedAuthResponse.js +3 -16
  76. package/dist/verifySignedAuthResponse.js.map +1 -1
  77. package/package.json +1 -1
@@ -26,21 +26,46 @@ function pruneRecentRefreshResults(now) {
26
26
  recentRefreshResults.delete(oldest);
27
27
  }
28
28
  }
29
- export async function refreshAccessToken(refreshCookie, opts) {
30
- assertSecrets(opts);
29
+ /**
30
+ * Runs one refresh per key at a time and replays a recent success to callers
31
+ * arriving just after it. The auth API rotates refresh tokens and treats a
32
+ * replay as theft, revoking the whole chain, so two requests that race the same
33
+ * token must be collapsed here rather than both reach it.
34
+ */
35
+ async function dedupeRefresh(key, run) {
31
36
  const now = Date.now();
32
- const recentRefresh = recentRefreshResults.get(refreshCookie);
37
+ const recentRefresh = recentRefreshResults.get(key);
33
38
  if (recentRefresh && recentRefresh.expiresAt > now) {
34
39
  return recentRefresh.result;
35
40
  }
36
41
  if (recentRefresh) {
37
- recentRefreshResults.delete(refreshCookie);
42
+ recentRefreshResults.delete(key);
38
43
  }
39
- const existingRefresh = inFlightRefreshes.get(refreshCookie);
44
+ const existingRefresh = inFlightRefreshes.get(key);
40
45
  if (existingRefresh) {
41
46
  return existingRefresh;
42
47
  }
43
- const refreshPromise = (async () => {
48
+ const refreshPromise = run();
49
+ inFlightRefreshes.set(key, refreshPromise);
50
+ try {
51
+ const result = await refreshPromise;
52
+ if (result) {
53
+ const insertedAt = Date.now();
54
+ pruneRecentRefreshResults(insertedAt);
55
+ recentRefreshResults.set(key, {
56
+ result,
57
+ expiresAt: insertedAt + RECENT_REFRESH_RESULT_TTL_MS,
58
+ });
59
+ }
60
+ return result;
61
+ }
62
+ finally {
63
+ inFlightRefreshes.delete(key);
64
+ }
65
+ }
66
+ export async function refreshAccessToken(refreshCookie, opts) {
67
+ assertSecrets(opts);
68
+ return dedupeRefresh(`cookie:${refreshCookie}`, async () => {
44
69
  const payload = verifyRefreshCookie(refreshCookie, opts.cookieSecret);
45
70
  if (!payload)
46
71
  return null;
@@ -62,22 +87,47 @@ export async function refreshAccessToken(refreshCookie, opts) {
62
87
  if (!response.ok)
63
88
  return null;
64
89
  return response.json();
65
- })();
66
- inFlightRefreshes.set(refreshCookie, refreshPromise);
67
- try {
68
- const result = await refreshPromise;
69
- if (result) {
70
- const insertedAt = Date.now();
71
- pruneRecentRefreshResults(insertedAt);
72
- recentRefreshResults.set(refreshCookie, {
73
- result,
74
- expiresAt: insertedAt + RECENT_REFRESH_RESULT_TTL_MS,
75
- });
76
- }
77
- return result;
90
+ });
91
+ }
92
+ class UpstreamRefreshFailure extends Error {
93
+ status;
94
+ body;
95
+ constructor(status, body) {
96
+ super(`Upstream refresh failed with ${status}`);
97
+ this.status = status;
98
+ this.body = body;
78
99
  }
79
- finally {
80
- inFlightRefreshes.delete(refreshCookie);
100
+ }
101
+ /**
102
+ * Rotates a session for a bearer client, which holds the raw refresh token.
103
+ *
104
+ * Unlike the cookie path this returns the auth API's failure as-is, because the
105
+ * client reads it: `refresh_token_reused` means the chain is gone and the user
106
+ * must sign in again, which is a different outcome from a transient failure.
107
+ */
108
+ export async function refreshBearerSession(refreshToken, opts) {
109
+ const rotated = await dedupeRefresh(`bearer:${refreshToken}`, async () => {
110
+ const response = await authFetch(`${opts.authServerUrl}/refresh`, {
111
+ method: "POST",
112
+ authorization: `Bearer ${refreshToken}`,
113
+ serviceAuthorization: opts.serviceAuthorization,
114
+ forwardedClientIp: opts.forwardedClientIp,
115
+ forwardedUserAgent: opts.forwardedUserAgent,
116
+ });
117
+ if (!response.ok) {
118
+ // Not cached, so a failed rotation is reported to every caller that
119
+ // asked for it rather than replayed as a success.
120
+ throw new UpstreamRefreshFailure(response.status, await response.json());
121
+ }
122
+ return response.json();
123
+ }).catch((error) => {
124
+ if (error instanceof UpstreamRefreshFailure)
125
+ return error;
126
+ throw error;
127
+ });
128
+ if (rotated instanceof UpstreamRefreshFailure) {
129
+ return { status: rotated.status, body: rotated.body };
81
130
  }
131
+ return { status: 200, body: rotated };
82
132
  }
83
133
  //# sourceMappingURL=refreshAccessToken.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"refreshAccessToken.js","sourceRoot":"","sources":["../src/refreshAccessToken.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"refreshAccessToken.js","sourceRoot":"","sources":["../src/refreshAccessToken.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * How a client carries its session through the adapter.
3
+ *
4
+ * `cookie` is the browser contract: the adapter holds the auth API's tokens in
5
+ * signed `httpOnly` cookies and the client never sees them. `bearer` is the
6
+ * native-client contract: the client holds the auth API's own tokens, presents
7
+ * the one a route needs in `Authorization`, and receives new ones in the
8
+ * response body. The adapter still sits in front of the auth API for both, so
9
+ * message delivery, client IP forwarding and the service token work the same.
10
+ */
11
+ export type AuthTransport = "cookie" | "bearer";
12
+ /**
13
+ * Selects bearer transport for a request. The header rather than the presence
14
+ * of `Authorization` decides, because the first request of a flow (`/login`,
15
+ * `/registration/register`) carries no token in either transport.
16
+ */
17
+ export declare const AUTH_TRANSPORT_HEADER = "x-seamless-auth-transport";
18
+ export declare const BEARER_TRANSPORT = "bearer";
19
+ export declare function resolveAuthTransport(headerValue: string | string[] | undefined): AuthTransport;
20
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AACjE,eAAO,MAAM,gBAAgB,WAAW,CAAC;AAEzC,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,GACzC,aAAa,CAIf"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Selects bearer transport for a request. The header rather than the presence
3
+ * of `Authorization` decides, because the first request of a flow (`/login`,
4
+ * `/registration/register`) carries no token in either transport.
5
+ */
6
+ export const AUTH_TRANSPORT_HEADER = "x-seamless-auth-transport";
7
+ export const BEARER_TRANSPORT = "bearer";
8
+ export function resolveAuthTransport(headerValue) {
9
+ const value = Array.isArray(headerValue) ? headerValue[0] : headerValue;
10
+ return value?.trim().toLowerCase() === BEARER_TRANSPORT ? "bearer" : "cookie";
11
+ }
12
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AAEzC,MAAM,UAAU,oBAAoB,CAClC,WAA0C;IAE1C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAExE,OAAO,KAAK,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AAChF,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import type { SessionCookie } from "./applyResult.js";
2
+ import type { AuthTransport } from "./transport.js";
2
3
  /**
3
4
  * What the auth API returns when it issues a session.
4
5
  *
@@ -65,4 +66,22 @@ export interface IssueSessionCookiesOptions {
65
66
  * cannot disagree about it.
66
67
  */
67
68
  export declare function issueSessionCookies(data: UpstreamSessionResponse, opts: IssueSessionCookiesOptions): Promise<SessionCookie[]>;
69
+ export interface SessionResultOptions extends IssueSessionCookiesOptions {
70
+ transport?: AuthTransport;
71
+ }
72
+ export interface SessionResult {
73
+ body: unknown;
74
+ setCookies?: SessionCookie[];
75
+ }
76
+ /**
77
+ * Turns an upstream session response into what a handler returns for it, in
78
+ * whichever transport the request arrived on.
79
+ *
80
+ * Cookie transport strips the tokens out of the body and carries them in
81
+ * cookies. Bearer transport hands the body back whole, tokens included, because
82
+ * the client is the one holding them. The upstream token is verified either
83
+ * way: a body this package is about to vouch for is checked before it goes out,
84
+ * whether or not a cookie is minted from it.
85
+ */
86
+ export declare function sessionResult(data: UpstreamSessionResponse, opts: SessionResultOptions): Promise<SessionResult>;
68
87
  //# sourceMappingURL=upstreamSession.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upstreamSession.d.ts","sourceRoot":"","sources":["../src/upstreamSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,uBAAuB,EAAE,IAAI,EAAE,CAAC,qCAIhF;AAED,MAAM,WAAW,uBAAuB;IACtC,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,uBAAuB,EAC7B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,uBAAuB,CAAC,CAkBlC;AAED,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,uBAAuB,EAC7B,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,aAAa,EAAE,CAAC,CAkC1B"}
1
+ {"version":3,"file":"upstreamSession.d.ts","sourceRoot":"","sources":["../src/upstreamSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,uBAAuB,EAAE,IAAI,EAAE,CAAC,qCAIhF;AAED,MAAM,WAAW,uBAAuB;IACtC,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,uBAAuB,EAC7B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,uBAAuB,CAAC,CAkBlC;AAED,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,uBAAuB,EAC7B,IAAI,EAAE,0BAA0B,GAC/B,OAAO,CAAC,aAAa,EAAE,CAAC,CAkC1B;AAED,MAAM,WAAW,oBAAqB,SAAQ,0BAA0B;IACtE,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,uBAAuB,EAC7B,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,aAAa,CAAC,CAUxB"}
@@ -71,4 +71,24 @@ export async function issueSessionCookies(data, opts) {
71
71
  }
72
72
  return cookies;
73
73
  }
74
+ /**
75
+ * Turns an upstream session response into what a handler returns for it, in
76
+ * whichever transport the request arrived on.
77
+ *
78
+ * Cookie transport strips the tokens out of the body and carries them in
79
+ * cookies. Bearer transport hands the body back whole, tokens included, because
80
+ * the client is the one holding them. The upstream token is verified either
81
+ * way: a body this package is about to vouch for is checked before it goes out,
82
+ * whether or not a cookie is minted from it.
83
+ */
84
+ export async function sessionResult(data, opts) {
85
+ if (opts.transport === "bearer") {
86
+ await verifyUpstreamSession(data, opts.authServerUrl, opts.audience);
87
+ return { body: data };
88
+ }
89
+ return {
90
+ body: withoutSessionMaterial(data),
91
+ setCookies: await issueSessionCookies(data, opts),
92
+ };
93
+ }
74
94
  //# sourceMappingURL=upstreamSession.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"upstreamSession.js","sourceRoot":"","sources":["../src/upstreamSession.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AA0BzE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CAAoC,IAAO;IAC/E,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAErE,OAAO,IAAI,CAAC;AACd,CAAC;AAOD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAA6B,EAC7B,aAAqB,EACrB,QAAgB;IAEhB,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC7C,IAAI,CAAC,KAAK,EACV,aAAa,EACb,QAAQ,CACT,CAAC;IAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,QAAQ,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO;QACL,SAAS,EAAE,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;KACvE,CAAC;AACJ,CAAC;AAWD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAA6B,EAC7B,IAAgC;IAEhC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,qBAAqB,CAC/C,IAAI,EACJ,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,QAAQ,CACd,CAAC;IAEF,MAAM,OAAO,GAAoB;QAC/B;YACE,IAAI,EAAE,IAAI,CAAC,gBAAgB;YAC3B,KAAK,EAAE;gBACL,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI;aAC5C;YACD,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,MAAM,EAAE,IAAI,CAAC,YAAY;SAC1B;KACF,CAAC;IAEF,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,IAAI,CAAC,iBAAiB;YAC5B,KAAK,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE;YACzD,GAAG,EAAE,IAAI,CAAC,UAAoB;YAC9B,MAAM,EAAE,IAAI,CAAC,YAAY;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"upstreamSession.js","sourceRoot":"","sources":["../src/upstreamSession.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AA0BzE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CAAoC,IAAO;IAC/E,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAErE,OAAO,IAAI,CAAC;AACd,CAAC;AAOD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAA6B,EAC7B,aAAqB,EACrB,QAAgB;IAEhB,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAC7C,IAAI,CAAC,KAAK,EACV,aAAa,EACb,QAAQ,CACT,CAAC;IAEF,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,QAAQ,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO;QACL,SAAS,EAAE,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;KACvE,CAAC;AACJ,CAAC;AAWD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,IAA6B,EAC7B,IAAgC;IAEhC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,qBAAqB,CAC/C,IAAI,EACJ,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,QAAQ,CACd,CAAC;IAEF,MAAM,OAAO,GAAoB;QAC/B;YACE,IAAI,EAAE,IAAI,CAAC,gBAAgB;YAC3B,KAAK,EAAE;gBACL,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,IAAI;aAC5C;YACD,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,MAAM,EAAE,IAAI,CAAC,YAAY;SAC1B;KACF,CAAC;IAEF,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,IAAI,CAAC,iBAAiB;YAC5B,KAAK,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE;YACzD,GAAG,EAAE,IAAI,CAAC,UAAoB;YAC9B,MAAM,EAAE,IAAI,CAAC,YAAY;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAWD;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAA6B,EAC7B,IAA0B;IAE1B,IAAI,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxB,CAAC;IAED,OAAO;QACL,IAAI,EAAE,sBAAsB,CAAC,IAAI,CAAC;QAClC,UAAU,EAAE,MAAM,mBAAmB,CAAC,IAAI,EAAE,IAAI,CAAC;KAClD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { type JWTPayload } from "jose";
2
+ /**
3
+ * The claims the auth API signs into an access token.
4
+ *
5
+ * `typ` is what separates a session from the ephemeral token a sign-in flow
6
+ * carries between steps. Both are RS256, both have the same issuer and
7
+ * audience, so a verifier that only checks the signature would accept a
8
+ * registration-in-progress as a signed-in user.
9
+ */
10
+ export interface AccessTokenClaims extends JWTPayload {
11
+ sub: string;
12
+ typ: "access";
13
+ sid?: string;
14
+ roles?: string[];
15
+ org_id?: string;
16
+ }
17
+ /**
18
+ * Returns a bearer token's value, or `undefined` when the header is absent or
19
+ * uses another scheme.
20
+ */
21
+ export declare function extractBearerToken(authorization: string | undefined): string | undefined;
22
+ /**
23
+ * Verifies an access token the auth API issued, against its JWKS.
24
+ *
25
+ * Silent on failure: a guard turns `null` into a 401 and has nothing useful to
26
+ * add from the reason, while logging the reason for every bad token a client
27
+ * sends is a log-flooding vector.
28
+ */
29
+ export declare function verifyAccessToken(token: string, authServerUrl: string, audience: string): Promise<AccessTokenClaims | null>;
30
+ //# sourceMappingURL=verifyAccessToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyAccessToken.d.ts","sourceRoot":"","sources":["../src/verifyAccessToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAGlD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,QAAQ,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,MAAM,GAAG,SAAS,GAChC,MAAM,GAAG,SAAS,CASpB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CA0BnC"}
@@ -0,0 +1,44 @@
1
+ import { jwtVerify } from "jose";
2
+ import { getAuthServerJwks } from "./jwks.js";
3
+ /**
4
+ * Returns a bearer token's value, or `undefined` when the header is absent or
5
+ * uses another scheme.
6
+ */
7
+ export function extractBearerToken(authorization) {
8
+ if (!authorization)
9
+ return undefined;
10
+ const [scheme, ...rest] = authorization.trim().split(/\s+/);
11
+ if (scheme?.toLowerCase() !== "bearer" || rest.length !== 1) {
12
+ return undefined;
13
+ }
14
+ return rest[0] || undefined;
15
+ }
16
+ /**
17
+ * Verifies an access token the auth API issued, against its JWKS.
18
+ *
19
+ * Silent on failure: a guard turns `null` into a 401 and has nothing useful to
20
+ * add from the reason, while logging the reason for every bad token a client
21
+ * sends is a log-flooding vector.
22
+ */
23
+ export async function verifyAccessToken(token, authServerUrl, audience) {
24
+ // jose skips the claim check for an empty expected value, which would turn a
25
+ // blank audience into "any audience". Refuse rather than verify loosely.
26
+ if (!authServerUrl || !audience) {
27
+ return null;
28
+ }
29
+ try {
30
+ const { payload } = await jwtVerify(token, getAuthServerJwks(authServerUrl), {
31
+ algorithms: ["RS256"],
32
+ issuer: authServerUrl,
33
+ audience,
34
+ });
35
+ if (payload.typ !== "access" || typeof payload.sub !== "string") {
36
+ return null;
37
+ }
38
+ return payload;
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ }
44
+ //# sourceMappingURL=verifyAccessToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyAccessToken.js","sourceRoot":"","sources":["../src/verifyAccessToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmB,MAAM,MAAM,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAkB9C;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAAiC;IAEjC,IAAI,CAAC,aAAa;QAAE,OAAO,SAAS,CAAC;IAErC,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,MAAM,EAAE,WAAW,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;AAC9B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,aAAqB,EACrB,QAAgB;IAEhB,6EAA6E;IAC7E,yEAAyE;IACzE,IAAI,CAAC,aAAa,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CACjC,KAAK,EACL,iBAAiB,CAAC,aAAa,CAAC,EAChC;YACE,UAAU,EAAE,CAAC,OAAO,CAAC;YACrB,MAAM,EAAE,aAAa;YACrB,QAAQ;SACT,CACF,CAAC;QAEF,IAAI,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,OAA4B,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"verifySignedAuthResponse.d.ts","sourceRoot":"","sources":["../src/verifySignedAuthResponse.ts"],"names":[],"mappings":"AAiBA,wBAAsB,wBAAwB,CAAC,CAAC,GAAG,GAAG,EACpD,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAkBnB"}
1
+ {"version":3,"file":"verifySignedAuthResponse.d.ts","sourceRoot":"","sources":["../src/verifySignedAuthResponse.ts"],"names":[],"mappings":"AAIA,wBAAsB,wBAAwB,CAAC,CAAC,GAAG,GAAG,EACpD,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAmBnB"}
@@ -1,22 +1,9 @@
1
- import { createRemoteJWKSet, jwtVerify } from "jose";
1
+ import { jwtVerify } from "jose";
2
+ import { getAuthServerJwks } from "./jwks.js";
2
3
  import { getSeamlessLogger } from "./logger.js";
3
- // jose caches keys and applies a refetch cooldown per JWKS instance, so the instance
4
- // must outlive a single call. Memoize per JWKS URL (one per auth server, so the map
5
- // stays tiny) instead of building a fresh, empty-cache instance on every verification.
6
- const jwksByUrl = new Map();
7
- function getJwks(jwksUrl) {
8
- let jwks = jwksByUrl.get(jwksUrl);
9
- if (!jwks) {
10
- jwks = createRemoteJWKSet(new URL(jwksUrl));
11
- jwksByUrl.set(jwksUrl, jwks);
12
- }
13
- return jwks;
14
- }
15
4
  export async function verifySignedAuthResponse(token, authServerUrl, audience) {
16
5
  try {
17
- const jwksUrl = new URL("/.well-known/jwks.json", authServerUrl).toString();
18
- const JWKS = getJwks(jwksUrl);
19
- const { payload } = await jwtVerify(token, JWKS, {
6
+ const { payload } = await jwtVerify(token, getAuthServerJwks(authServerUrl), {
20
7
  algorithms: ["RS256"],
21
8
  issuer: authServerUrl,
22
9
  audience,
@@ -1 +1 @@
1
- {"version":3,"file":"verifySignedAuthResponse.js","sourceRoot":"","sources":["../src/verifySignedAuthResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,qFAAqF;AACrF,oFAAoF;AACpF,uFAAuF;AACvF,MAAM,SAAS,GAAG,IAAI,GAAG,EAAiD,CAAC;AAE3E,SAAS,OAAO,CAAC,OAAe;IAC9B,IAAI,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,GAAG,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5C,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAAa,EACb,aAAqB,EACrB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,wBAAwB,EAAE,aAAa,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAE9B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;YAC/C,UAAU,EAAE,CAAC,OAAO,CAAC;YACrB,MAAM,EAAE,aAAa;YACrB,QAAQ;SACT,CAAC,CAAC;QAEH,OAAO,OAAY,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB,EAAE,CAAC,KAAK,CACvB,uDAAuD,CACxD,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"verifySignedAuthResponse.js","sourceRoot":"","sources":["../src/verifySignedAuthResponse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAAa,EACb,aAAqB,EACrB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CACjC,KAAK,EACL,iBAAiB,CAAC,aAAa,CAAC,EAChC;YACE,UAAU,EAAE,CAAC,OAAO,CAAC;YACrB,MAAM,EAAE,aAAa;YACrB,QAAQ;SACT,CACF,CAAC;QAEF,OAAO,OAAY,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB,EAAE,CAAC,KAAK,CACvB,uDAAuD,CACxD,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamless-auth/core",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Framework-agnostic core authentication logic for SeamlessAuth",
5
5
  "keywords": [
6
6
  "authentication",