@revealui/auth 0.4.10 → 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/dist/react/useSignIn.d.ts +1 -1
- package/dist/react/useSignIn.d.ts.map +1 -1
- package/dist/react/useSignIn.js +7 -3
- package/dist/server/audit-storage.d.ts +122 -0
- package/dist/server/audit-storage.d.ts.map +1 -0
- package/dist/server/audit-storage.js +298 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +68 -10
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +9 -0
- package/dist/server/platform-roles.d.ts +42 -0
- package/dist/server/platform-roles.d.ts.map +1 -0
- package/dist/server/platform-roles.js +65 -0
- package/dist/server/session.js +1 -1
- package/dist/server/sso/__tests__/helpers/mock-oidc-idp.d.ts +31 -0
- package/dist/server/sso/__tests__/helpers/mock-oidc-idp.d.ts.map +1 -0
- package/dist/server/sso/__tests__/helpers/mock-oidc-idp.js +115 -0
- package/dist/server/sso/__tests__/helpers/mock-saml-idp.d.ts +28 -0
- package/dist/server/sso/__tests__/helpers/mock-saml-idp.d.ts.map +1 -0
- package/dist/server/sso/__tests__/helpers/mock-saml-idp.js +150 -0
- package/dist/server/sso/index.d.ts +13 -0
- package/dist/server/sso/index.d.ts.map +1 -0
- package/dist/server/sso/index.js +12 -0
- package/dist/server/sso/jit.d.ts +39 -0
- package/dist/server/sso/jit.d.ts.map +1 -0
- package/dist/server/sso/jit.js +141 -0
- package/dist/server/sso/oidc.d.ts +137 -0
- package/dist/server/sso/oidc.d.ts.map +1 -0
- package/dist/server/sso/oidc.js +345 -0
- package/dist/server/sso/roles.d.ts +48 -0
- package/dist/server/sso/roles.d.ts.map +1 -0
- package/dist/server/sso/roles.js +109 -0
- package/dist/server/sso/saml.d.ts +99 -0
- package/dist/server/sso/saml.d.ts.map +1 -0
- package/dist/server/sso/saml.js +392 -0
- package/dist/server/sso/state.d.ts +46 -0
- package/dist/server/sso/state.d.ts.map +1 -0
- package/dist/server/sso/state.js +101 -0
- package/dist/utils/database.d.ts +1 -1
- package/dist/utils/database.d.ts.map +1 -1
- package/package.json +15 -6
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enterprise SSO signed state cookie (GAP-464).
|
|
3
|
+
*
|
|
4
|
+
* Separate from social OAuth generateOAuthState / verifyOAuthState so enterprise
|
|
5
|
+
* IdP bindings (accountId + providerId + PKCE) never overload provider enums.
|
|
6
|
+
*
|
|
7
|
+
* Cookie value: `<state>.<hmac-hex>` where state is base64url(JSON payload)
|
|
8
|
+
* and HMAC-SHA256 is over the state string using REVEALUI_SECRET.
|
|
9
|
+
*/
|
|
10
|
+
import crypto from 'node:crypto';
|
|
11
|
+
function requireSecret() {
|
|
12
|
+
const secret = process.env.REVEALUI_SECRET;
|
|
13
|
+
if (!secret) {
|
|
14
|
+
throw new Error('REVEALUI_SECRET is required for SSO state signing. ' +
|
|
15
|
+
'Set it in your environment variables.');
|
|
16
|
+
}
|
|
17
|
+
return secret;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate a signed SSO state token with PKCE verifier.
|
|
21
|
+
*/
|
|
22
|
+
export function generateSsoState(input) {
|
|
23
|
+
const { accountId, providerId, redirectTo } = input;
|
|
24
|
+
if (!(accountId && providerId)) {
|
|
25
|
+
throw new Error('accountId and providerId are required for SSO state');
|
|
26
|
+
}
|
|
27
|
+
const nonce = crypto.randomBytes(16).toString('hex');
|
|
28
|
+
const codeVerifier = crypto.randomBytes(32).toString('base64url');
|
|
29
|
+
const codeChallenge = crypto.createHash('sha256').update(codeVerifier).digest('base64url');
|
|
30
|
+
const payload = {
|
|
31
|
+
accountId,
|
|
32
|
+
providerId,
|
|
33
|
+
redirectTo,
|
|
34
|
+
nonce,
|
|
35
|
+
codeVerifier,
|
|
36
|
+
};
|
|
37
|
+
const state = Buffer.from(JSON.stringify(payload)).toString('base64url');
|
|
38
|
+
const secret = requireSecret();
|
|
39
|
+
// lgtm[js/insufficient-password-hash] - HMAC-SHA256 for SSO CSRF state, not password hashing
|
|
40
|
+
const hmac = crypto.createHmac('sha256', secret).update(state).digest('hex');
|
|
41
|
+
return {
|
|
42
|
+
state,
|
|
43
|
+
cookieValue: `${state}.${hmac}`,
|
|
44
|
+
codeChallenge,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Verify a signed SSO state token from the callback.
|
|
49
|
+
* Returns null on any integrity / shape failure (does not throw for bad input).
|
|
50
|
+
*/
|
|
51
|
+
export function verifySsoState(state, cookieValue) {
|
|
52
|
+
if (!(state && cookieValue))
|
|
53
|
+
return null;
|
|
54
|
+
const dotIdx = cookieValue.lastIndexOf('.');
|
|
55
|
+
if (dotIdx === -1)
|
|
56
|
+
return null;
|
|
57
|
+
const storedState = cookieValue.substring(0, dotIdx);
|
|
58
|
+
const storedHmac = cookieValue.substring(dotIdx + 1);
|
|
59
|
+
if (storedState.length !== state.length ||
|
|
60
|
+
!crypto.timingSafeEqual(Buffer.from(storedState), Buffer.from(state))) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const secret = requireSecret();
|
|
64
|
+
// lgtm[js/insufficient-password-hash] - HMAC-SHA256 for SSO CSRF state, not password hashing
|
|
65
|
+
const expectedHmac = crypto.createHmac('sha256', secret).update(state).digest('hex');
|
|
66
|
+
// Both are hex-encoded SHA-256 HMACs — must be exactly 64 hex characters.
|
|
67
|
+
if (storedHmac.length !== 64 || expectedHmac.length !== 64)
|
|
68
|
+
return null;
|
|
69
|
+
try {
|
|
70
|
+
if (!crypto.timingSafeEqual(Buffer.from(storedHmac, 'hex'), Buffer.from(expectedHmac, 'hex'))) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const parsed = JSON.parse(Buffer.from(state, 'base64url').toString());
|
|
79
|
+
if (typeof parsed.accountId !== 'string' ||
|
|
80
|
+
typeof parsed.providerId !== 'string' ||
|
|
81
|
+
typeof parsed.redirectTo !== 'string' ||
|
|
82
|
+
typeof parsed.nonce !== 'string' ||
|
|
83
|
+
typeof parsed.codeVerifier !== 'string' ||
|
|
84
|
+
!parsed.accountId ||
|
|
85
|
+
!parsed.providerId ||
|
|
86
|
+
!parsed.nonce ||
|
|
87
|
+
!parsed.codeVerifier) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
accountId: parsed.accountId,
|
|
92
|
+
providerId: parsed.providerId,
|
|
93
|
+
redirectTo: parsed.redirectTo,
|
|
94
|
+
nonce: parsed.nonce,
|
|
95
|
+
codeVerifier: parsed.codeVerifier,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
package/dist/utils/database.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export declare function getTestDatabaseUrl(): string;
|
|
|
18
18
|
/**
|
|
19
19
|
* Creates a test database client
|
|
20
20
|
*/
|
|
21
|
-
export declare function createTestDatabaseClient(): import("@revealui/db
|
|
21
|
+
export declare function createTestDatabaseClient(): import("@revealui/db").DatabaseClient;
|
|
22
22
|
/**
|
|
23
23
|
* Cleans up test data from database
|
|
24
24
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/utils/database.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAU3C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/utils/database.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAU3C;AAED;;GAEG;AACH,wBAAgB,wBAAwB,0CAMvC;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBtE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B7E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAC3B,OAAO,CAAC,OAAO,CAAC,CAuBlB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CASxE;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAStF;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,aAAa,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAClC,OAAO,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAI3C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revealui/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Database-backed session auth for Hono and Next.js — bcrypt, OAuth, brute-force protection, rate limiting, password reset. Ships with RevealUI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"auth",
|
|
@@ -10,15 +10,17 @@
|
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"@node-saml/node-saml": "5.1.0",
|
|
13
14
|
"@simplewebauthn/server": "^13.3.2",
|
|
14
15
|
"bcryptjs": "^3.0.3",
|
|
15
16
|
"drizzle-orm": "^0.45.2",
|
|
17
|
+
"jose": "^5.10.0",
|
|
16
18
|
"zod": "^4.4.3",
|
|
17
19
|
"@revealui/config": "0.6.0",
|
|
18
|
-
"@revealui/contracts": "0.8.
|
|
19
|
-
"@revealui/core": "0.12.
|
|
20
|
-
"@revealui/db": "0.
|
|
21
|
-
"@revealui/security": "0.
|
|
20
|
+
"@revealui/contracts": "0.8.2",
|
|
21
|
+
"@revealui/core": "0.12.4",
|
|
22
|
+
"@revealui/db": "0.10.0",
|
|
23
|
+
"@revealui/security": "0.6.1"
|
|
22
24
|
},
|
|
23
25
|
"devDependencies": {
|
|
24
26
|
"@simplewebauthn/browser": "^13.3.0",
|
|
@@ -27,9 +29,11 @@
|
|
|
27
29
|
"@types/react": "^19.2.17",
|
|
28
30
|
"@vitest/coverage-v8": "^4.1.10",
|
|
29
31
|
"happy-dom": "^20.10.6",
|
|
30
|
-
"react": "
|
|
32
|
+
"react": "19.2.8",
|
|
33
|
+
"selfsigned": "2.4.1",
|
|
31
34
|
"typescript": "^6.0.3",
|
|
32
35
|
"vitest": "^4.1.10",
|
|
36
|
+
"xml-crypto": "6.1.2",
|
|
33
37
|
"@revealui/dev": "0.1.0"
|
|
34
38
|
},
|
|
35
39
|
"engines": {
|
|
@@ -46,6 +50,11 @@
|
|
|
46
50
|
"import": "./dist/server/index.js",
|
|
47
51
|
"default": "./dist/server/index.js"
|
|
48
52
|
},
|
|
53
|
+
"./audit-storage": {
|
|
54
|
+
"types": "./dist/server/audit-storage.d.ts",
|
|
55
|
+
"import": "./dist/server/audit-storage.js",
|
|
56
|
+
"default": "./dist/server/audit-storage.js"
|
|
57
|
+
},
|
|
49
58
|
"./react": {
|
|
50
59
|
"types": "./dist/react/index.d.ts",
|
|
51
60
|
"import": "./dist/react/index.js",
|