@seamless-auth/core 0.5.1-beta.20260523225720 → 0.5.1

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/README.md CHANGED
@@ -88,6 +88,7 @@ Key exports include:
88
88
  - `refreshAccessToken(...)` – rotates expired access sessions
89
89
  - `verifyCookieJwt(...)` – verifies signed cookie payloads
90
90
  - `createServiceToken(...)` – creates short-lived M2M assertions
91
+ - `hasScopedRole(...)` – checks scoped role grants such as `admin:read`
91
92
  - `listOAuthProvidersHandler(...)` – retrieves public OAuth provider metadata
92
93
  - `startOAuthLoginHandler(...)` – starts an OAuth authorization-code login
93
94
  - `finishOAuthLoginHandler(...)` – finishes OAuth login and returns cookie instructions
@@ -172,6 +173,23 @@ provider identity linking. Core and adapter code never store provider access tok
172
173
 
173
174
  ---
174
175
 
176
+ ## Scoped Roles
177
+
178
+ Core exports `hasScopedRole` and `roleGrantsAccess` for framework adapters and custom servers that
179
+ need the same authorization semantics as `@seamless-auth/express`.
180
+
181
+ ```ts
182
+ import { hasScopedRole } from "@seamless-auth/core";
183
+
184
+ hasScopedRole(["admin:write"], "admin:read"); // true
185
+ hasScopedRole(["admin:read"], "admin:write"); // false
186
+ ```
187
+
188
+ Plain roles remain backwards compatible. `admin` grants `admin:read` and `admin:write`, while
189
+ `admin:read` does not satisfy a plain `admin` check.
190
+
191
+ ---
192
+
175
193
  ## Testing
176
194
 
177
195
  All logic in this package is tested against compiled output (`dist/`),
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export * from "./verifyCookieJwt.js";
5
5
  export * from "./refreshAccessToken.js";
6
6
  export * from "./getSeamlessUser.js";
7
7
  export * from "./createServiceToken.js";
8
+ export * from "./scopedRoles.js";
8
9
  export * from "./handlers/login.js";
9
10
  export * from "./handlers/finishLogin.js";
10
11
  export * from "./handlers/register.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AAExC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AAEjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ export * from "./verifyCookieJwt.js";
5
5
  export * from "./refreshAccessToken.js";
6
6
  export * from "./getSeamlessUser.js";
7
7
  export * from "./createServiceToken.js";
8
+ export * from "./scopedRoles.js";
8
9
  export * from "./handlers/login.js";
9
10
  export * from "./handlers/finishLogin.js";
10
11
  export * from "./handlers/register.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AAExC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AAEjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function roleGrantsAccess(grantedRole: string, requiredRole: string): boolean;
2
+ export declare function hasScopedRole(grantedRoles: unknown, requiredRoles: string | string[]): boolean;
3
+ //# sourceMappingURL=scopedRoles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopedRoles.d.ts","sourceRoot":"","sources":["../src/scopedRoles.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAsCnF;AAED,wBAAgB,aAAa,CAC3B,YAAY,EAAE,OAAO,EACrB,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,GAC/B,OAAO,CAaT"}
@@ -0,0 +1,39 @@
1
+ export function roleGrantsAccess(grantedRole, requiredRole) {
2
+ const granted = grantedRole.trim();
3
+ const required = requiredRole.trim();
4
+ if (!granted || !required) {
5
+ return false;
6
+ }
7
+ if (granted === required) {
8
+ return true;
9
+ }
10
+ if (granted.endsWith(":*")) {
11
+ const prefix = granted.slice(0, -2);
12
+ return required === prefix || required.startsWith(`${prefix}:`);
13
+ }
14
+ if (!required.includes(":")) {
15
+ return false;
16
+ }
17
+ if (!granted.includes(":")) {
18
+ return required.startsWith(`${granted}:`);
19
+ }
20
+ const grantedParts = granted.split(":");
21
+ const requiredParts = required.split(":");
22
+ const grantedAction = grantedParts.at(-1);
23
+ const requiredAction = requiredParts.at(-1);
24
+ const grantedPrefix = grantedParts.slice(0, -1);
25
+ const requiredPrefix = requiredParts.slice(0, -1);
26
+ return (grantedAction === "write" &&
27
+ requiredAction === "read" &&
28
+ grantedPrefix.length === requiredPrefix.length &&
29
+ grantedPrefix.every((part, index) => part === requiredPrefix[index]));
30
+ }
31
+ export function hasScopedRole(grantedRoles, requiredRoles) {
32
+ if (!Array.isArray(grantedRoles)) {
33
+ return false;
34
+ }
35
+ const granted = grantedRoles.filter((role) => typeof role === "string");
36
+ const required = Array.isArray(requiredRoles) ? requiredRoles : [requiredRoles];
37
+ return required.some((requiredRole) => granted.some((grantedRole) => roleGrantsAccess(grantedRole, requiredRole)));
38
+ }
39
+ //# sourceMappingURL=scopedRoles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopedRoles.js","sourceRoot":"","sources":["../src/scopedRoles.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,YAAoB;IACxE,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;IAErC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpC,OAAO,QAAQ,KAAK,MAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,aAAa,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,cAAc,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,cAAc,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAElD,OAAO,CACL,aAAa,KAAK,OAAO;QACzB,cAAc,KAAK,MAAM;QACzB,aAAa,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM;QAC9C,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,cAAc,CAAC,KAAK,CAAC,CAAC,CACrE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,YAAqB,EACrB,aAAgC;IAEhC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CACjC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CACnD,CAAC;IACF,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAEhF,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CACpC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamless-auth/core",
3
- "version": "0.5.1-beta.20260523225720",
3
+ "version": "0.5.1",
4
4
  "description": "Framework-agnostic core authentication logic for SeamlessAuth",
5
5
  "license": "AGPL-3.0-only",
6
6
  "author": "Fells Code, LLC",