@eventuras/fides-auth 0.4.0 → 0.6.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.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { configureLogger as e, createLogger as t } from "./logger.js";
2
- import { a as n, c as r, d as i, i as a, l as o, n as s, o as c, r as l, s as u, t as d, u as f } from "./utils-ByMRF7b2.js";
3
- import { n as p, t as m } from "./session-validation-BxObT3wC.js";
4
- import { refreshSession as h } from "./session-refresh.js";
2
+ import { a as n, c as r, d as i, f as a, i as o, l as s, n as c, o as l, r as u, s as d, t as f, u as p } from "./utils-C0OavYxH.js";
3
+ import { n as m, t as h } from "./session-validation-CHSsh4q_.js";
4
+ import { refreshSession as g } from "./session-refresh.js";
5
5
  import "./types.js";
6
- export { d as accessTokenExpires, e as configureLogger, s as createEncryptedJWT, t as createLogger, l as decrypt, a as encrypt, n as generateToken, c as getSessionSecret, u as getSessionSecretUint8Array, r as hexToUint8Array, m as isSession, h as refreshSession, o as sha256, f as sha512, i as toHex, p as validateSessionJwt };
6
+ export { f as accessTokenExpires, e as configureLogger, c as createEncryptedJWT, t as createLogger, u as decrypt, o as encrypt, n as generateToken, l as getSessionSecret, d as getSessionSecretUint8Array, r as hasScope, s as hexToUint8Array, h as isSession, g as refreshSession, p as sha256, i as sha512, a as toHex, m as validateSessionJwt };
package/dist/oauth.d.ts CHANGED
@@ -10,6 +10,14 @@ export type OAuthConfig = {
10
10
  clientSecret: string;
11
11
  redirect_uri: string;
12
12
  scope: string;
13
+ /**
14
+ * Opt in to Pushed Authorization Requests (RFC 9126) when the provider
15
+ * supports it. When true, authorization parameters are posted to the
16
+ * provider's PAR endpoint ahead of the redirect, and only `client_id` +
17
+ * `request_uri` travel through the user-agent. The provider must advertise
18
+ * `pushed_authorization_request_endpoint` in its discovery metadata.
19
+ */
20
+ usePar?: boolean;
13
21
  };
14
22
  /**
15
23
  * Refreshes an access token using a refresh token grant.
@@ -46,8 +54,27 @@ export declare function buildPKCEOptions(config: OAuthConfig): Promise<PKCEOptio
46
54
  */
47
55
  export declare function buildAuthorizationUrl(config: openid.Configuration, pkceOptions: PKCEOptions): Promise<URL>;
48
56
  /**
49
- * Convenience function to discover OpenID configuration and build authorization URL.
50
- * This combines discovery + buildAuthorizationUrl in one call.
57
+ * Builds an authorization URL using Pushed Authorization Requests (RFC 9126).
58
+ *
59
+ * Posts the PKCE parameters to the provider's PAR endpoint and returns a URL
60
+ * containing only `client_id` and `request_uri`. The provider's discovery
61
+ * metadata must include `pushed_authorization_request_endpoint`.
62
+ *
63
+ * @param config - Discovered OpenID Configuration (use openid.discovery() to obtain)
64
+ * @param pkceOptions - The PKCE options (e.g., code challenge, state, parameters)
65
+ * @returns A Promise that resolves to the PAR-based authorization URL
66
+ */
67
+ export declare function buildAuthorizationUrlWithPAR(config: openid.Configuration, pkceOptions: PKCEOptions): Promise<URL>;
68
+ /**
69
+ * Convenience function to discover OpenID configuration and build an
70
+ * authorization URL. Routes through PAR when `oauthConfig.usePar` is true and
71
+ * the provider advertises `pushed_authorization_request_endpoint`.
72
+ *
73
+ * - `usePar === true` + provider advertises PAR → uses PAR.
74
+ * - `usePar === true` + provider does **not** advertise PAR → throws.
75
+ * - `usePar` unset/false + provider advertises PAR → standard flow + one-line
76
+ * `info` advisory that PAR is available but not enabled.
77
+ * - `usePar` unset/false + no PAR endpoint → standard flow, no advisory.
51
78
  *
52
79
  * @param oauthConfig - Your OAuth configuration
53
80
  * @param pkceOptions - The PKCE options (e.g., code challenge, state, parameters)
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
package/dist/oauth.js CHANGED
@@ -1,85 +1,98 @@
1
1
  import { createLogger as e } from "./logger.js";
2
2
  import { t } from "./decode_jwt-1J26fl4I.js";
3
- import { a as n, c as r, i, n as a, o, r as s, s as c, t as l } from "./build-BnXr85C9.js";
3
+ import { a as n, c as r, i, l as a, n as o, o as s, r as c, s as l, t as u } from "./build-nL2--iMi.js";
4
4
  //#region src/oauth.ts
5
- var u = e({ namespace: "fides-auth:oauth" }), d = "openid profile email offline_access";
6
- async function f(e, t) {
7
- u.debug({ issuer: e.issuer }, "Starting token refresh");
5
+ var d = e({ namespace: "fides-auth:oauth" }), f = "openid profile email offline_access";
6
+ async function p(e, t) {
7
+ d.debug({ issuer: e.issuer }, "Starting token refresh");
8
8
  try {
9
- let i = await r(await n(new URL(e.issuer), e.clientId, e.clientSecret, l(e.clientSecret)), t, { scope: e.scope });
10
- return u.info({
11
- hasAccessToken: !!i.access_token,
12
- hasRefreshToken: !!i.refresh_token,
13
- expiresIn: i.expires_in
14
- }, "Token refresh successful"), i;
9
+ let n = await a(await s(new URL(e.issuer), e.clientId, e.clientSecret, u(e.clientSecret)), t, { scope: e.scope });
10
+ return d.info({
11
+ hasAccessToken: !!n.access_token,
12
+ hasRefreshToken: !!n.refresh_token,
13
+ expiresIn: n.expires_in
14
+ }, "Token refresh successful"), n;
15
15
  } catch (t) {
16
16
  let n = t;
17
- throw n?.code === "OAUTH_RESPONSE_BODY_ERROR" && n?.error === "invalid_grant" ? u.info({
17
+ throw n?.code === "OAUTH_RESPONSE_BODY_ERROR" && n?.error === "invalid_grant" ? d.info({
18
18
  error: n.error,
19
19
  error_description: n.error_description,
20
20
  issuer: e.issuer
21
- }, "Token refresh failed - refresh token expired or invalid") : u.error({
21
+ }, "Token refresh failed - refresh token expired or invalid") : d.error({
22
22
  error: t,
23
23
  issuer: e.issuer
24
24
  }, "Token refresh failed"), t;
25
25
  }
26
26
  }
27
- async function p(e) {
28
- let t = o(), n = await i(t), r = c(), a = {
27
+ async function m(e) {
28
+ let t = l(), i = await n(t), a = r(), o = {
29
29
  redirect_uri: e.redirect_uri,
30
30
  scope: e.scope ?? "openid profile email offline_access",
31
- code_challenge: n,
31
+ code_challenge: i,
32
32
  code_challenge_method: "S256",
33
- state: r
33
+ state: a
34
34
  };
35
- return u.info({
35
+ return d.info({
36
36
  redirectUri: e.redirect_uri,
37
- scope: a.scope
37
+ scope: o.scope
38
38
  }, "PKCE parameters generated"), {
39
39
  code_verifier: t,
40
- code_challenge: n,
41
- state: r,
42
- parameters: a
40
+ code_challenge: i,
41
+ state: a,
42
+ parameters: o
43
43
  };
44
44
  }
45
- async function m(e, t) {
45
+ async function h(e, t) {
46
46
  try {
47
- let n = s(e, t.parameters);
48
- return u.info({ authUrl: n.origin }, "Authorization URL built successfully"), n;
47
+ let n = c(e, t.parameters);
48
+ return d.info("Authorization URL built successfully"), n;
49
49
  } catch (e) {
50
- throw u.error({ error: e }, "Failed to build authorization URL"), e;
50
+ throw d.error({ error: e }, "Failed to build authorization URL"), e;
51
51
  }
52
52
  }
53
- async function h(e, t) {
54
- u.debug({ issuer: e.issuer }, "Discovering OpenID configuration");
53
+ async function g(e, t) {
54
+ try {
55
+ let n = await i(e, t.parameters);
56
+ return d.info("PAR authorization URL built successfully"), n;
57
+ } catch (e) {
58
+ throw d.error({ error: e }, "Failed to build PAR authorization URL"), e;
59
+ }
60
+ }
61
+ async function _(e, t) {
62
+ d.debug({ issuer: e.issuer }, "Discovering OpenID configuration");
55
63
  try {
56
- return m(await n(new URL(e.issuer), e.clientId, e.clientSecret, l(e.clientSecret)), t);
64
+ let n = await s(new URL(e.issuer), e.clientId, e.clientSecret, u(e.clientSecret)), r = n.serverMetadata().pushed_authorization_request_endpoint;
65
+ if (e.usePar) {
66
+ if (!r) throw Error("PAR requested (usePar=true) but provider does not advertise pushed_authorization_request_endpoint");
67
+ return g(n, t);
68
+ }
69
+ return r && d.info({ issuer: e.issuer }, "Provider advertises PAR but usePar is not enabled — set OAuthConfig.usePar=true to use it"), h(n, t);
57
70
  } catch (t) {
58
- throw u.error({
71
+ throw d.error({
59
72
  error: t,
60
73
  issuer: e.issuer
61
74
  }, "Failed to discover config or build URL"), t;
62
75
  }
63
76
  }
64
- async function g(e, t, r, i) {
65
- u.debug({
77
+ async function v(e, t, n, r) {
78
+ d.debug({
66
79
  issuer: e.issuer,
67
80
  clientId: e.clientId
68
81
  }, "Exchanging authorization code for tokens");
69
- let o = await a(await n(new URL(e.issuer), e.clientId, e.clientSecret, l(e.clientSecret)), t, {
70
- pkceCodeVerifier: r,
71
- expectedState: i
82
+ let i = await o(await s(new URL(e.issuer), e.clientId, e.clientSecret, u(e.clientSecret)), t, {
83
+ pkceCodeVerifier: n,
84
+ expectedState: r
72
85
  }, { redirect_uri: e.redirect_uri });
73
- return u.info({
74
- hasAccessToken: !!o.access_token,
75
- hasRefreshToken: !!o.refresh_token,
76
- expiresIn: o.expires_in
77
- }, "Authorization code exchange successful"), o;
86
+ return d.info({
87
+ hasAccessToken: !!i.access_token,
88
+ hasRefreshToken: !!i.refresh_token,
89
+ expiresIn: i.expires_in
90
+ }, "Authorization code exchange successful"), i;
78
91
  }
79
- function _(e, n = "roles") {
92
+ function y(e, n = "roles") {
80
93
  if (!e.id_token) throw Error("OIDC token response is missing id_token");
81
94
  let r = t(e.id_token), i = r[n], a = typeof i == "string" ? [i] : [], o = Array.isArray(i) ? i : a;
82
- return u.debug({
95
+ return d.debug({
83
96
  sub: r.sub,
84
97
  rolesClaim: n,
85
98
  rolesCount: o.length
@@ -90,9 +103,13 @@ function _(e, n = "roles") {
90
103
  roles: o
91
104
  };
92
105
  }
93
- function v(e, t = "roles") {
106
+ function b(e, t = "roles") {
94
107
  if (!e.access_token) throw Error("OIDC token response is missing access_token");
95
- let n = _(e, t);
108
+ let n = y(e, t), r;
109
+ if (typeof e.scope == "string") {
110
+ let t = e.scope.split(" ").filter((e) => e.length > 0);
111
+ t.length > 0 && (r = t);
112
+ }
96
113
  return {
97
114
  tokens: {
98
115
  accessToken: e.access_token,
@@ -103,37 +120,38 @@ function v(e, t = "roles") {
103
120
  name: n.name,
104
121
  email: n.email,
105
122
  roles: n.roles
106
- }
123
+ },
124
+ scopes: r
107
125
  };
108
126
  }
109
- function y(e, t, n = "/", r) {
127
+ function x(e, t, n = "/", r) {
110
128
  let i = e ?? n, a;
111
129
  try {
112
130
  a = new URL(i, t);
113
131
  } catch {
114
- return u.warn({ returnTo: i }, "Invalid returnTo URL, using default"), new URL(n, t);
132
+ return d.warn({ returnTo: i }, "Invalid returnTo URL, using default"), new URL(n, t);
115
133
  }
116
134
  let o = new URL(t);
117
- return a.origin === o.origin ? r && !r(a.pathname) ? (u.warn({ pathname: a.pathname }, "returnTo failed custom validation, falling back to default"), new URL(n, t)) : a : (u.error({
135
+ return a.origin === o.origin ? r && !r(a.pathname) ? (d.warn({ pathname: a.pathname }, "returnTo failed custom validation, falling back to default"), new URL(n, t)) : a : (d.error({
118
136
  returnTo: i,
119
137
  redirectOrigin: a.origin,
120
138
  applicationOrigin: o.origin
121
139
  }, "Possible open redirect attack: returnTo points outside application origin"), new URL(n, t));
122
140
  }
123
- async function b(e, t) {
141
+ async function S(e, t) {
124
142
  try {
125
- let r = (await n(new URL(e.issuer), e.clientId, e.clientSecret, l(e.clientSecret))).serverMetadata().end_session_endpoint;
126
- if (!r) return u.info({ issuer: e.issuer }, "No end_session_endpoint found"), null;
127
- let i = new URL(r);
128
- return i.searchParams.set("client_id", e.clientId), i.searchParams.set("post_logout_redirect_uri", t), u.debug({ logoutUrl: i.toString() }, "Built OIDC logout URL"), i;
143
+ let n = (await s(new URL(e.issuer), e.clientId, e.clientSecret, u(e.clientSecret))).serverMetadata().end_session_endpoint;
144
+ if (!n) return d.info({ issuer: e.issuer }, "No end_session_endpoint found"), null;
145
+ let r = new URL(n);
146
+ return r.searchParams.set("client_id", e.clientId), r.searchParams.set("post_logout_redirect_uri", t), d.debug({ logoutUrl: r.toString() }, "Built OIDC logout URL"), r;
129
147
  } catch (t) {
130
- return u.warn({
148
+ return d.warn({
131
149
  error: t,
132
150
  issuer: e.issuer
133
151
  }, "OIDC discovery failed for logout"), null;
134
152
  }
135
153
  }
136
- async function x(e) {
154
+ async function C(e) {
137
155
  try {
138
156
  let t = new URLSearchParams({
139
157
  grant_type: "client_credentials",
@@ -148,18 +166,18 @@ async function x(e) {
148
166
  });
149
167
  if (!n.ok) {
150
168
  let e = await n.text();
151
- throw u.error({
169
+ throw d.error({
152
170
  status: n.status,
153
171
  error: e
154
172
  }, "Client credentials grant failed"), Error(`Client credentials grant failed: ${n.status} - ${e}`);
155
173
  }
156
174
  return await n.json();
157
175
  } catch (t) {
158
- throw u.error({
176
+ throw d.error({
159
177
  error: t,
160
178
  tokenEndpoint: e.tokenEndpoint
161
179
  }, "Client credentials grant error"), t;
162
180
  }
163
181
  }
164
182
  //#endregion
165
- export { m as buildAuthorizationUrl, b as buildOidcLogoutUrl, p as buildPKCEOptions, v as buildSessionFromTokens, x as clientCredentialsGrant, d as defaultScope, h as discoverAndBuildAuthorizationUrl, g as exchangeAuthorizationCode, _ as extractUserFromTokens, f as refreshAccessToken, y as validateReturnUrl };
183
+ export { h as buildAuthorizationUrl, g as buildAuthorizationUrlWithPAR, S as buildOidcLogoutUrl, m as buildPKCEOptions, b as buildSessionFromTokens, C as clientCredentialsGrant, f as defaultScope, _ as discoverAndBuildAuthorizationUrl, v as exchangeAuthorizationCode, y as extractUserFromTokens, p as refreshAccessToken, x as validateReturnUrl };
@@ -1,5 +1,5 @@
1
1
  import { createLogger as e } from "../../logger.js";
2
- import { a as t, c as n, n as r, t as i } from "../../build-BnXr85C9.js";
2
+ import { l as t, n, o as r, t as i } from "../../build-nL2--iMi.js";
3
3
  import { buildAuthorizationUrl as a, buildPKCEOptions as o } from "../../oauth.js";
4
4
  //#region src/providers/vipps/types.ts
5
5
  var s = {
@@ -48,7 +48,7 @@ var d = e({
48
48
  }, "VippsLoginClient initialized");
49
49
  }
50
50
  async getConfig() {
51
- return this.configPromise ||= t(new URL(this.oauthConfig.issuer), this.oauthConfig.clientId, this.oauthConfig.clientSecret, i(this.oauthConfig.clientSecret)), this.configPromise;
51
+ return this.configPromise ||= r(new URL(this.oauthConfig.issuer), this.oauthConfig.clientId, this.oauthConfig.clientSecret, i(this.oauthConfig.clientSecret)), this.configPromise;
52
52
  }
53
53
  async buildPKCEOptions() {
54
54
  return d.debug("Building PKCE options"), o(this.oauthConfig);
@@ -56,12 +56,12 @@ var d = e({
56
56
  async buildAuthorizationUrl(e) {
57
57
  return d.debug("Building authorization URL"), a(await this.getConfig(), e);
58
58
  }
59
- async exchangeCodeForTokens(e, t, n) {
59
+ async exchangeCodeForTokens(e, t, r) {
60
60
  d.debug("Exchanging authorization code for tokens");
61
61
  try {
62
- let i = await r(await this.getConfig(), typeof e == "string" ? new URL(e) : e, {
62
+ let i = await n(await this.getConfig(), typeof e == "string" ? new URL(e) : e, {
63
63
  pkceCodeVerifier: t,
64
- expectedState: n,
64
+ expectedState: r,
65
65
  idTokenExpected: !0
66
66
  });
67
67
  return d.info({
@@ -105,12 +105,12 @@ var d = e({
105
105
  async refreshTokens(e) {
106
106
  d.debug("Refreshing access token");
107
107
  try {
108
- let t = await n(await this.getConfig(), e);
108
+ let n = await t(await this.getConfig(), e);
109
109
  return d.info({
110
- hasAccessToken: !!t.access_token,
111
- hasRefreshToken: !!t.refresh_token,
112
- expiresIn: t.expires_in
113
- }, "Successfully refreshed tokens"), t;
110
+ hasAccessToken: !!n.access_token,
111
+ hasRefreshToken: !!n.refresh_token,
112
+ expiresIn: n.expires_in
113
+ }, "Successfully refreshed tokens"), n;
114
114
  } catch (e) {
115
115
  throw d.error({ error: e }, "Failed to refresh tokens"), e;
116
116
  }
@@ -1,7 +1,7 @@
1
1
  import { createLogger as e } from "./logger.js";
2
2
  import { y as t } from "./deflate-koSuX7FB.js";
3
3
  import { t as n } from "./decrypt-Cahlu_6Y.js";
4
- import { c as r, f as i } from "./utils-ByMRF7b2.js";
4
+ import { l as r, p as i } from "./utils-C0OavYxH.js";
5
5
  import { t as a } from "./decode_jwt-1J26fl4I.js";
6
6
  //#region ../../node_modules/.pnpm/jose@6.2.2/node_modules/jose/dist/webapi/jwt/decrypt.js
7
7
  async function o(e, r, a) {
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "./session-validation-BxObT3wC.js";
1
+ import { n as e, t } from "./session-validation-CHSsh4q_.js";
2
2
  export { t as isSession, e as validateSessionJwt };
@@ -1,5 +1,5 @@
1
1
  import { createLogger as e } from "./logger.js";
2
- import { a as t, r as n, t as r } from "./build-BnXr85C9.js";
2
+ import { o as t, r as n, t as r } from "./build-nL2--iMi.js";
3
3
  //#region src/silent-login.ts
4
4
  var i = e({ namespace: "fides-auth:silent-login" });
5
5
  async function a(e, a = {}) {
package/dist/types.d.ts CHANGED
@@ -13,6 +13,8 @@ export interface Session<TData = Record<string, unknown>> {
13
13
  email: string;
14
14
  roles?: string[];
15
15
  };
16
+ /** OAuth scopes granted to this session (e.g. ["openid", "profile", "email"]). */
17
+ scopes?: string[];
16
18
  /** Application-specific data stored alongside the session. */
17
19
  data?: TData;
18
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,MAAM,WAAW,MAAM;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,IAAI,CAAC;CAC9B;AAED,mFAAmF;AACnF,MAAM,WAAW,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;IACF,8DAA8D;IAC9D,IAAI,CAAC,EAAE,KAAK,CAAC;CACd;AAED,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,MAAM,WAAW,MAAM;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,IAAI,CAAC;CAC9B;AAED,mFAAmF;AACnF,MAAM,WAAW,OAAO,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;IACF,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,KAAK,CAAC;CACd;AAED,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B"}
@@ -375,5 +375,8 @@ var Z = (e, t = 10) => {
375
375
  return R.error({ error: e }, "Error decoding access token"), !0;
376
376
  }
377
377
  };
378
+ function Q(e, t) {
379
+ return e.scopes?.includes(t) ?? !1;
380
+ }
378
381
  //#endregion
379
- export { X as a, z as c, Y as d, P as f, H as i, G as l, V as n, q as o, U as r, J as s, Z as t, K as u };
382
+ export { X as a, Q as c, K as d, Y as f, H as i, z as l, V as n, q as o, P as p, U as r, J as s, Z as t, G as u };
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Session } from './types';
1
2
  /**
2
3
  * Converts a hex string to a Uint8Array.
3
4
  *
@@ -80,4 +81,11 @@ export declare function generateToken(tokenLength?: number): string;
80
81
  * @returns True if the access token expires within the threshold; otherwise, false.
81
82
  */
82
83
  export declare const accessTokenExpires: (accessToken: string, seconds?: number) => boolean;
84
+ /**
85
+ * Returns true if the session was granted the given scope.
86
+ *
87
+ * @param session - The session to check
88
+ * @param scope - The scope string to look for (e.g. "operations.read")
89
+ */
90
+ export declare function hasScope(session: Session, scope: string): boolean;
83
91
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAYvD;AAaD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,GAAG,UAAU,GAC1B,OAAO,CAAC,MAAM,CAAC,CAKjB;AAGD;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAkCxF;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA4CxF;AAcD;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAIvE;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAIvE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,IAAI,UAAU,CAKvD;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAI/C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,WAAW,GAAE,MAAW,GAAG,MAAM,CAI9D;AAGD;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC7B,aAAa,MAAM,EACnB,UAAS,MAAW,KACnB,OAsBF,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAKvC;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAYvD;AAaD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,GAAG,UAAU,GAC1B,OAAO,CAAC,MAAM,CAAC,CAKjB;AAGD;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAkCxF;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA4CxF;AAcD;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAIvE;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAIvE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,IAAI,UAAU,CAKvD;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAI/C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,WAAW,GAAE,MAAW,GAAG,MAAM,CAI9D;AAGD;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC7B,aAAa,MAAM,EACnB,UAAS,MAAW,KACnB,OAsBF,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjE"}
package/dist/utils.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as e, c as t, d as n, i as r, l as i, n as a, o, r as s, s as c, t as l, u } from "./utils-ByMRF7b2.js";
2
- export { l as accessTokenExpires, a as createEncryptedJWT, s as decrypt, r as encrypt, e as generateToken, o as getSessionSecret, c as getSessionSecretUint8Array, t as hexToUint8Array, i as sha256, u as sha512, n as toHex };
1
+ import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "./utils-C0OavYxH.js";
2
+ export { u as accessTokenExpires, o as createEncryptedJWT, c as decrypt, i as encrypt, e as generateToken, s as getSessionSecret, l as getSessionSecretUint8Array, t as hasScope, a as hexToUint8Array, d as sha256, n as sha512, r as toHex };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventuras/fides-auth",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Framework-agnostic OAuth/OIDC authentication library with PKCE, session management, and pluggable logging",
5
5
  "keywords": [
6
6
  "oauth",
@@ -87,8 +87,8 @@
87
87
  "@types/node": "^25.6.0",
88
88
  "vite": "^8.0.8",
89
89
  "vitest": "^4.1.4",
90
- "@eventuras/typescript-config": "1.0.0",
91
- "@eventuras/vite-config": "0.2.1"
90
+ "@eventuras/vite-config": "0.2.1",
91
+ "@eventuras/typescript-config": "1.0.0"
92
92
  },
93
93
  "engines": {
94
94
  "node": ">=18"