kavachos 0.0.6 → 0.1.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/README.md +170 -37
- package/dist/a2a/index.d.ts +2 -1
- package/dist/agent/index.d.ts +3 -2
- package/dist/audit/index.d.ts +2 -1
- package/dist/auth/index.d.ts +3 -2
- package/dist/auth/index.js +1 -1
- package/dist/{chunk-FKVAXCNJ.js → chunk-IEOOSOJ4.js} +72 -30
- package/dist/chunk-IEOOSOJ4.js.map +1 -0
- package/dist/chunk-YARXM6MQ.js +288 -0
- package/dist/chunk-YARXM6MQ.js.map +1 -0
- package/dist/crypto/index.d.ts +55 -0
- package/dist/crypto/index.js +4 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/index.d.ts +7 -57
- package/dist/index.js +12 -292
- package/dist/index.js.map +1 -1
- package/dist/permission/index.d.ts +3 -2
- package/dist/redirect/index.d.ts +118 -0
- package/dist/redirect/index.js +5 -0
- package/dist/redirect/index.js.map +1 -0
- package/dist/{types-W8X0PXE7.d.ts → types-6D7iJvGD.d.ts} +4 -120
- package/package.json +2 -1
- package/dist/chunk-FKVAXCNJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,69 +1,202 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://kavachos.com/logo.svg" height="64" alt="KavachOS" />
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">kavachos</h1>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>The auth OS for AI agents and humans</strong><br />
|
|
9
|
+
Identity, permissions, delegation, and audit for the agentic era.
|
|
10
|
+
</p>
|
|
7
11
|
|
|
8
|
-
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.npmjs.com/package/kavachos"><img src="https://img.shields.io/npm/v/kavachos?style=flat-square&color=c9a84c" alt="npm" /></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/kavachos"><img src="https://img.shields.io/npm/dm/kavachos?style=flat-square&color=c9a84c" alt="downloads" /></a>
|
|
15
|
+
<a href="https://github.com/kavachos/kavachos/actions"><img src="https://img.shields.io/github/actions/workflow/status/kavachos/kavachos/ci.yml?style=flat-square&label=tests" alt="tests" /></a>
|
|
16
|
+
<a href="https://github.com/kavachos/kavachos/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="MIT" /></a>
|
|
17
|
+
<a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-strict-blue?style=flat-square" alt="TypeScript" /></a>
|
|
18
|
+
<a href="https://docs.kavachos.com"><img src="https://img.shields.io/badge/docs-kavachos.com-c9a84c?style=flat-square" alt="docs" /></a>
|
|
19
|
+
</p>
|
|
9
20
|
|
|
10
|
-
|
|
21
|
+
<p align="center">
|
|
22
|
+
<a href="https://docs.kavachos.com/docs/quickstart">Quickstart</a> ·
|
|
23
|
+
<a href="https://docs.kavachos.com/docs">Documentation</a> ·
|
|
24
|
+
<a href="https://github.com/kavachos/kavachos/tree/main/examples">Examples</a> ·
|
|
25
|
+
<a href="https://app.kavachos.com">KavachOS Cloud</a>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Why kavachos?
|
|
31
|
+
|
|
32
|
+
Every auth library handles human login. None of them handle **AI agent identity**. KavachOS gives every agent its own bearer token, scoped permissions, delegation chains, and an immutable audit trail. Plus full human auth (14 methods, 27+ OAuth providers, passkeys, SSO) so you don't need two auth systems.
|
|
33
|
+
|
|
34
|
+
```
|
|
11
35
|
npm install kavachos
|
|
12
|
-
# or
|
|
13
|
-
pnpm add kavachos
|
|
14
36
|
```
|
|
15
37
|
|
|
16
38
|
## Quick start
|
|
17
39
|
|
|
18
40
|
```typescript
|
|
19
|
-
import { createKavach } from
|
|
41
|
+
import { createKavach } from "kavachos";
|
|
42
|
+
import { emailPassword } from "kavachos/auth";
|
|
20
43
|
|
|
21
44
|
const kavach = createKavach({
|
|
22
|
-
database: { provider:
|
|
45
|
+
database: { provider: "sqlite", url: "kavach.db" },
|
|
46
|
+
plugins: [emailPassword()],
|
|
23
47
|
});
|
|
24
48
|
|
|
25
|
-
// Create an agent with scoped permissions
|
|
49
|
+
// Create an AI agent with scoped permissions
|
|
26
50
|
const agent = await kavach.agent.create({
|
|
27
|
-
ownerId:
|
|
28
|
-
name:
|
|
29
|
-
type:
|
|
51
|
+
ownerId: "user-123",
|
|
52
|
+
name: "github-reader",
|
|
53
|
+
type: "autonomous",
|
|
30
54
|
permissions: [
|
|
31
|
-
{ resource:
|
|
32
|
-
{
|
|
33
|
-
|
|
34
|
-
actions: ['execute'],
|
|
35
|
-
constraints: { requireApproval: true },
|
|
36
|
-
},
|
|
55
|
+
{ resource: "mcp:github:*", actions: ["read"] },
|
|
56
|
+
{ resource: "mcp:deploy:production", actions: ["execute"],
|
|
57
|
+
constraints: { requireApproval: true } },
|
|
37
58
|
],
|
|
38
59
|
});
|
|
39
60
|
|
|
40
|
-
// Authorize
|
|
61
|
+
// Authorize and audit (< 1ms)
|
|
41
62
|
const result = await kavach.authorize(agent.id, {
|
|
42
|
-
action:
|
|
43
|
-
resource:
|
|
63
|
+
action: "read",
|
|
64
|
+
resource: "mcp:github:repos",
|
|
44
65
|
});
|
|
45
|
-
// { allowed: true, auditId:
|
|
66
|
+
// { allowed: true, auditId: "aud_..." }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Features
|
|
70
|
+
|
|
71
|
+
<table>
|
|
72
|
+
<tr>
|
|
73
|
+
<td width="50%">
|
|
74
|
+
|
|
75
|
+
### Agent identity
|
|
76
|
+
- Cryptographic bearer tokens (`kv_...`)
|
|
77
|
+
- Wildcard permission matching (`mcp:github:*`)
|
|
78
|
+
- Delegation chains with depth limits
|
|
79
|
+
- Immutable audit trail
|
|
80
|
+
- Trust scoring and anomaly detection
|
|
81
|
+
- Budget policies and cost attribution
|
|
82
|
+
- CIBA-style human approval flows
|
|
83
|
+
|
|
84
|
+
</td>
|
|
85
|
+
<td width="50%">
|
|
86
|
+
|
|
87
|
+
### Human auth (14 methods)
|
|
88
|
+
- Email + password
|
|
89
|
+
- Magic link, email OTP
|
|
90
|
+
- Passkey / WebAuthn
|
|
91
|
+
- TOTP 2FA
|
|
92
|
+
- Phone SMS
|
|
93
|
+
- Google One-tap
|
|
94
|
+
- Sign In With Ethereum
|
|
95
|
+
- Anonymous auth
|
|
96
|
+
- Session freshness enforcement
|
|
97
|
+
|
|
98
|
+
</td>
|
|
99
|
+
</tr>
|
|
100
|
+
<tr>
|
|
101
|
+
<td>
|
|
102
|
+
|
|
103
|
+
### OAuth (27+ providers)
|
|
104
|
+
Google, GitHub, Apple, Microsoft, Discord, Slack, GitLab, LinkedIn, Twitter/X, Facebook, Spotify, Twitch, Reddit, Notion, plus a generic OIDC factory for any provider.
|
|
105
|
+
|
|
106
|
+
</td>
|
|
107
|
+
<td>
|
|
108
|
+
|
|
109
|
+
### MCP OAuth 2.1
|
|
110
|
+
Spec-compliant authorization server for Model Context Protocol. PKCE S256, RFC 9728 / 8707 / 8414 / 7591.
|
|
111
|
+
|
|
112
|
+
</td>
|
|
113
|
+
</tr>
|
|
114
|
+
<tr>
|
|
115
|
+
<td>
|
|
116
|
+
|
|
117
|
+
### Enterprise
|
|
118
|
+
Organizations + RBAC, SAML SSO, SCIM directory sync, admin controls, API key management, multi-tenant isolation, GDPR compliance.
|
|
119
|
+
|
|
120
|
+
</td>
|
|
121
|
+
<td>
|
|
122
|
+
|
|
123
|
+
### Edge compatible
|
|
124
|
+
Runs on Cloudflare Workers (D1), Deno, Bun, and Node.js. Only 3 runtime deps: `drizzle-orm`, `jose`, `zod`.
|
|
46
125
|
|
|
47
|
-
|
|
48
|
-
|
|
126
|
+
</td>
|
|
127
|
+
</tr>
|
|
128
|
+
</table>
|
|
129
|
+
|
|
130
|
+
### Security
|
|
131
|
+
|
|
132
|
+
Rate limiting (per-agent and per-IP) · HIBP breach checking · CSRF protection · httpOnly secure cookies · Email enumeration prevention · Trusted device windows · Password reset with signed tokens
|
|
133
|
+
|
|
134
|
+
## Framework adapters
|
|
135
|
+
|
|
136
|
+
Works with every major framework:
|
|
137
|
+
|
|
138
|
+
| Framework | Package | Framework | Package |
|
|
139
|
+
|-----------|---------|-----------|---------|
|
|
140
|
+
| **Hono** | `@kavachos/hono` | **Nuxt** | `@kavachos/nuxt` |
|
|
141
|
+
| **Express** | `@kavachos/express` | **SvelteKit** | `@kavachos/sveltekit` |
|
|
142
|
+
| **Next.js** | `@kavachos/nextjs` | **Astro** | `@kavachos/astro` |
|
|
143
|
+
| **Fastify** | `@kavachos/fastify` | **NestJS** | `@kavachos/nestjs` |
|
|
144
|
+
|
|
145
|
+
## Client libraries
|
|
146
|
+
|
|
147
|
+
| Package | What |
|
|
148
|
+
|---------|------|
|
|
149
|
+
| `@kavachos/react` | KavachProvider + hooks |
|
|
150
|
+
| `@kavachos/vue` | Vue 3 plugin + composables |
|
|
151
|
+
| `@kavachos/svelte` | Svelte stores |
|
|
152
|
+
| `@kavachos/ui` | 7 pre-built auth components (SignIn, SignUp, UserButton...) |
|
|
153
|
+
| `@kavachos/expo` | React Native / Expo |
|
|
154
|
+
| `@kavachos/electron` | Electron desktop |
|
|
155
|
+
| `@kavachos/client` | Zero-dep TypeScript REST client |
|
|
156
|
+
|
|
157
|
+
## Databases
|
|
158
|
+
|
|
159
|
+
SQLite, PostgreSQL, MySQL, Cloudflare D1, libSQL (Turso). Tables are auto-created on first run.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Cloudflare Workers + D1
|
|
163
|
+
createKavach({ database: { provider: "d1", binding: env.KAVACH_DB } });
|
|
164
|
+
|
|
165
|
+
// PostgreSQL
|
|
166
|
+
createKavach({ database: { provider: "postgres", url: process.env.DATABASE_URL } });
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Plugins
|
|
170
|
+
|
|
171
|
+
Auth methods are plugins. Enable what you need:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import {
|
|
175
|
+
emailPassword, magicLink, passkey, totp,
|
|
176
|
+
organizations, sso, admin, apiKeys, webhooks,
|
|
177
|
+
} from "kavachos/auth";
|
|
178
|
+
|
|
179
|
+
createKavach({
|
|
180
|
+
database: { provider: "sqlite", url: "kavach.db" },
|
|
181
|
+
plugins: [emailPassword(), magicLink({ sendMagicLink }), passkey(), totp()],
|
|
182
|
+
});
|
|
49
183
|
```
|
|
50
184
|
|
|
51
|
-
##
|
|
185
|
+
## KavachOS Cloud
|
|
52
186
|
|
|
53
|
-
|
|
54
|
-
- **Permission engine** - resource-based access control with colon-separated hierarchies (`mcp:github:*`) and wildcard matching. Constraints support rate limits, time windows, and human-in-the-loop approval gates.
|
|
55
|
-
- **Delegation chains** - an orchestrator can delegate a subset of its permissions to a sub-agent, with depth limits and expiry. Chains are auditable and revocable at any point.
|
|
56
|
-
- **Audit trail** - every authorization decision is written to an immutable log. Export as JSON or CSV for EU AI Act Article 12, SOC 2 CC6.1-CC7.2, and ISO 42001 compliance.
|
|
57
|
-
- **MCP OAuth 2.1** - spec-compliant authorization server for the Model Context Protocol, with PKCE (S256), Protected Resource Metadata (RFC 9728), and Resource Indicators (RFC 8707).
|
|
187
|
+
Don't want to self-host? [KavachOS Cloud](https://app.kavachos.com) is the managed version with dashboard, billing, and zero infrastructure.
|
|
58
188
|
|
|
59
|
-
|
|
189
|
+
| | Free | Starter | Growth | Scale |
|
|
190
|
+
|---|---|---|---|---|
|
|
191
|
+
| MAU | 1,000 | 10,000 | 50,000 | 200,000 |
|
|
192
|
+
| Price | $0 | $29/mo | $79/mo | $199/mo |
|
|
60
193
|
|
|
61
|
-
[kavachos.com/
|
|
194
|
+
[Start free](https://app.kavachos.com/sign-up) · [Compare plans](https://kavachos.com/pricing) · [Self-host instead](https://docs.kavachos.com/docs/quickstart)
|
|
62
195
|
|
|
63
|
-
##
|
|
196
|
+
## Documentation
|
|
64
197
|
|
|
65
|
-
[
|
|
198
|
+
Full docs at **[docs.kavachos.com](https://docs.kavachos.com/docs)**
|
|
66
199
|
|
|
67
200
|
## License
|
|
68
201
|
|
|
69
|
-
MIT
|
|
202
|
+
[MIT](https://github.com/kavachos/kavachos/blob/main/LICENSE)
|
package/dist/a2a/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as jose from 'jose';
|
|
2
|
-
import { A as AgentIdentity } from '../types-
|
|
2
|
+
import { A as AgentIdentity } from '../types-6D7iJvGD.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { R as Result } from '../types-BuHrZcjE.js';
|
|
5
5
|
import 'drizzle-orm/sqlite-core';
|
|
6
|
+
import '../redirect/index.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* A2A (Agent-to-Agent) protocol types for KavachOS.
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { D as Database, C as CreateAgentInput, A as AgentIdentity, h as AgentFilter, U as UpdateAgentInput } from '../types-
|
|
2
|
-
export {
|
|
1
|
+
import { D as Database, C as CreateAgentInput, A as AgentIdentity, h as AgentFilter, U as UpdateAgentInput } from '../types-6D7iJvGD.js';
|
|
2
|
+
export { Y as AgentConfig } from '../types-6D7iJvGD.js';
|
|
3
3
|
import 'drizzle-orm/sqlite-core';
|
|
4
4
|
import '../types-BuHrZcjE.js';
|
|
5
5
|
import 'zod';
|
|
6
|
+
import '../redirect/index.js';
|
|
6
7
|
|
|
7
8
|
interface AgentModuleConfig {
|
|
8
9
|
db: Database;
|
package/dist/audit/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { D as Database, k as AuditFilter, l as AuditEntry, m as AuditExportOptions } from '../types-
|
|
1
|
+
import { D as Database, k as AuditFilter, l as AuditEntry, m as AuditExportOptions } from '../types-6D7iJvGD.js';
|
|
2
2
|
import 'drizzle-orm/sqlite-core';
|
|
3
3
|
import '../types-BuHrZcjE.js';
|
|
4
4
|
import 'zod';
|
|
5
|
+
import '../redirect/index.js';
|
|
5
6
|
|
|
6
7
|
interface AuditModuleConfig {
|
|
7
8
|
db: Database;
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
export { u as AdminModule,
|
|
2
|
+
import { a1 as AuthAdapter, o as ResolvedUser, J as KavachPlugin, D as Database, Q as AdminConfig, p as SessionManager, _ as ApiKeyManagerConfig, a6 as EmailOtpConfig, P as Permission, aa as MagicLinkConfig, af as OrgConfig, ak as PasskeyConfig, H as PluginEndpoint, aB as TotpConfig } from '../types-6D7iJvGD.js';
|
|
3
|
+
export { u as AdminModule, X as AdminUser, Z as ApiKey, v as ApiKeyManagerModule, a2 as CaptchaConfig, G as CaptchaModule, a3 as CaptchaVerifyResult, a4 as CreateTokenInput, E as EmailOtpModule, a7 as EmailVerificationConfig, y as EmailVerificationModule, r as MagicLinkModule, ac as OidcProvider, ad as OneTimeTokenConfig, z as OneTimeTokenModule, ae as OneTimeTokenPurpose, ag as OrgInvitation, ah as OrgMember, O as OrgModule, ai as OrgRole, aj as Organization, al as PasskeyCredential, s as PasskeyModule, am as PasswordResetConfig, x as PasswordResetModule, ao as PhoneAuthConfig, F as PhoneAuthModule, ar as RevokeTokensResult, as as SSO_ERROR, at as SamlProvider, aw as SsoAuditEvent, ax as SsoConfig, ay as SsoConnection, az as SsoError, t as SsoModule, T as TotpModule, aC as TotpSetup, aD as UsernameAuthConfig, w as UsernameAuthModule, aE as ValidateTokenResult, bq as WebhookConfig, br as WebhookEvent, W as WebhookModule, aO as createAdminModule, aP as createApiKeyManagerModule, aR as createCaptchaModule, aU as createEmailOtpModule, aV as createEmailVerificationModule, aW as createMagicLinkModule, aX as createOneTimeTokenModule, aY as createOrgModule, aZ as createPasskeyModule, a_ as createPasswordResetModule, a$ as createPhoneAuthModule, b2 as createSsoModule, b3 as createTotpModule, b4 as createUsernameAuthModule, bs as createWebhookModule } from '../types-6D7iJvGD.js';
|
|
4
4
|
import { R as Result } from '../types-BuHrZcjE.js';
|
|
5
5
|
import * as jose from 'jose';
|
|
6
6
|
import 'drizzle-orm/sqlite-core';
|
|
7
|
+
import '../redirect/index.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* JWT bearer-token auth adapter.
|
package/dist/auth/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { EVENT_TYPES, HibpApiError, HibpBreachedError, OAuthProxyError, OneTapVerifyError, SSO_ERROR, SsoError, additionalFields, admin, anonymousAuth, apiKeys, bearerAuth, createAdditionalFieldsModule, createAdminModule, createAnonymousAuthModule, createApiKeyManagerModule, createCaptchaModule, createCostAttributionModule, createCustomSessionModule, createDeviceAuthModule, createEmailOtpModule, createEmailVerificationModule, createEphemeralSessionModule, createEventStreamModule, createFederationModule, createGdprModule, createHibpModule, createJwtSessionModule, createLastLoginModule, createMagicLinkModule, createOAuthProxyModule, createOidcProviderModule, createOneTapModule, createOneTimeTokenModule, createOpenApiModule, createOrgModule, createPasskeyModule, createPasswordResetModule, createPhoneAuthModule, createPolarModule, createRateLimiter, createReBACModule, createScimModule, createSiweModule, createSsoModule, createStripeModule, createTotpModule, createTrustedDeviceModule, createUsernameAuthModule, createWebhookModule, customAuth, customSession, deviceAuth, deviceLabelFromRequest, emailOtp, gdpr, headerAuth, magicLink, oauthProxy, oneTap, organization, passkey, polar, scim, siwe, stripe, twoFactor, withRateLimit } from '../chunk-
|
|
1
|
+
export { EVENT_TYPES, HibpApiError, HibpBreachedError, OAuthProxyError, OneTapVerifyError, SSO_ERROR, SsoError, additionalFields, admin, anonymousAuth, apiKeys, bearerAuth, createAdditionalFieldsModule, createAdminModule, createAnonymousAuthModule, createApiKeyManagerModule, createCaptchaModule, createCostAttributionModule, createCustomSessionModule, createDeviceAuthModule, createEmailOtpModule, createEmailVerificationModule, createEphemeralSessionModule, createEventStreamModule, createFederationModule, createGdprModule, createHibpModule, createJwtSessionModule, createLastLoginModule, createMagicLinkModule, createOAuthProxyModule, createOidcProviderModule, createOneTapModule, createOneTimeTokenModule, createOpenApiModule, createOrgModule, createPasskeyModule, createPasswordResetModule, createPhoneAuthModule, createPolarModule, createRateLimiter, createReBACModule, createScimModule, createSiweModule, createSsoModule, createStripeModule, createTotpModule, createTrustedDeviceModule, createUsernameAuthModule, createWebhookModule, customAuth, customSession, deviceAuth, deviceLabelFromRequest, emailOtp, gdpr, headerAuth, magicLink, oauthProxy, oneTap, organization, passkey, polar, scim, siwe, stripe, twoFactor, withRateLimit } from '../chunk-IEOOSOJ4.js';
|
|
2
2
|
import '../chunk-KDL6A76K.js';
|
|
3
3
|
import '../chunk-QCRHJMDX.js';
|
|
4
4
|
import '../chunk-NSBPE2FW.js';
|
|
@@ -4,8 +4,6 @@ import * as jose2 from 'jose';
|
|
|
4
4
|
import { jwtVerify, SignJWT, createRemoteJWKSet, importJWK } from 'jose';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { eq, like, sql, lt, and, gte, lte, asc, desc, gt, inArray, or, notInArray } from 'drizzle-orm';
|
|
7
|
-
import { randomUUID, createHash, randomBytes as randomBytes$1, createVerify } from 'crypto';
|
|
8
|
-
import { TextEncoder as TextEncoder$1 } from 'util';
|
|
9
7
|
import { deflateRaw } from 'zlib';
|
|
10
8
|
|
|
11
9
|
var BearerAuthOptionsSchema = z.object({
|
|
@@ -10548,7 +10546,7 @@ function getSamlAttributeValue(assertion, attributeName) {
|
|
|
10548
10546
|
return null;
|
|
10549
10547
|
}
|
|
10550
10548
|
function deflateRawAsync(input) {
|
|
10551
|
-
const encoder = new TextEncoder
|
|
10549
|
+
const encoder = new TextEncoder();
|
|
10552
10550
|
return new Promise((resolve, reject) => {
|
|
10553
10551
|
deflateRaw(encoder.encode(input), (err2, result) => {
|
|
10554
10552
|
if (err2) reject(err2);
|
|
@@ -10564,14 +10562,33 @@ function uint8ArrayToBase64(bytes) {
|
|
|
10564
10562
|
return btoa(binary);
|
|
10565
10563
|
}
|
|
10566
10564
|
async function buildSamlAuthnRequest(provider) {
|
|
10567
|
-
const requestId = `_${
|
|
10565
|
+
const requestId = `_${randomBytesHex(16)}`;
|
|
10568
10566
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10569
10567
|
const xml = `<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="${requestId}" Version="2.0" IssueInstant="${now}" Destination="${provider.entryPoint}" AssertionConsumerServiceURL="${provider.callbackUrl}"><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">${provider.entityId ?? provider.issuer}</saml:Issuer></samlp:AuthnRequest>`;
|
|
10570
10568
|
const deflated = await deflateRawAsync(xml);
|
|
10571
10569
|
const b64 = uint8ArrayToBase64(deflated);
|
|
10572
10570
|
return { requestId, encoded: encodeURIComponent(b64) };
|
|
10573
10571
|
}
|
|
10574
|
-
function
|
|
10572
|
+
function pemToArrayBuffer(pem) {
|
|
10573
|
+
const base64 = pem.replace(/-----[^-]+-----/g, "").replace(/\s+/g, "");
|
|
10574
|
+
const binary = atob(base64);
|
|
10575
|
+
const bytes = new Uint8Array(binary.length);
|
|
10576
|
+
for (let i = 0; i < binary.length; i++) {
|
|
10577
|
+
bytes[i] = binary.charCodeAt(i);
|
|
10578
|
+
}
|
|
10579
|
+
return bytes.buffer;
|
|
10580
|
+
}
|
|
10581
|
+
function base64ToArrayBuffer(b64) {
|
|
10582
|
+
let base64 = b64.replace(/-/g, "+").replace(/_/g, "/");
|
|
10583
|
+
while (base64.length % 4 !== 0) base64 += "=";
|
|
10584
|
+
const binary = atob(base64);
|
|
10585
|
+
const bytes = new Uint8Array(binary.length);
|
|
10586
|
+
for (let i = 0; i < binary.length; i++) {
|
|
10587
|
+
bytes[i] = binary.charCodeAt(i);
|
|
10588
|
+
}
|
|
10589
|
+
return bytes.buffer;
|
|
10590
|
+
}
|
|
10591
|
+
async function verifySamlSignature(doc, certPem) {
|
|
10575
10592
|
const signatureNode = findElement(doc, "Signature");
|
|
10576
10593
|
if (!signatureNode) return false;
|
|
10577
10594
|
const signedInfoNode = findElement(signatureNode, "SignedInfo");
|
|
@@ -10617,15 +10634,22 @@ function verifySamlSignature(doc, certPem) {
|
|
|
10617
10634
|
referencedContent = removeSignatureFromXml(doc.rawOuterXml);
|
|
10618
10635
|
}
|
|
10619
10636
|
if (referencedContent && expectedDigest) {
|
|
10620
|
-
let
|
|
10637
|
+
let digestHashName;
|
|
10621
10638
|
if (digestAlgo.includes("sha256") || digestAlgo.includes("SHA256")) {
|
|
10622
|
-
|
|
10639
|
+
digestHashName = "SHA-256";
|
|
10623
10640
|
} else if (digestAlgo.includes("sha1") || digestAlgo.includes("SHA1")) {
|
|
10624
|
-
|
|
10641
|
+
digestHashName = "SHA-1";
|
|
10625
10642
|
} else {
|
|
10626
|
-
|
|
10643
|
+
digestHashName = "SHA-256";
|
|
10644
|
+
}
|
|
10645
|
+
const contentBuf = new TextEncoder().encode(referencedContent);
|
|
10646
|
+
const digestBuf = await globalThis.crypto.subtle.digest(digestHashName, contentBuf);
|
|
10647
|
+
const digestBytes = new Uint8Array(digestBuf);
|
|
10648
|
+
let digestBinary = "";
|
|
10649
|
+
for (let i = 0; i < digestBytes.length; i++) {
|
|
10650
|
+
digestBinary += String.fromCharCode(digestBytes[i]);
|
|
10627
10651
|
}
|
|
10628
|
-
const actualDigest =
|
|
10652
|
+
const actualDigest = btoa(digestBinary);
|
|
10629
10653
|
if (actualDigest !== expectedDigest) {
|
|
10630
10654
|
return false;
|
|
10631
10655
|
}
|
|
@@ -10635,10 +10659,24 @@ function verifySamlSignature(doc, certPem) {
|
|
|
10635
10659
|
const normalizedCert = certPem.includes("-----") ? certPem : `-----BEGIN CERTIFICATE-----
|
|
10636
10660
|
${certPem}
|
|
10637
10661
|
-----END CERTIFICATE-----`;
|
|
10638
|
-
const verifier = createVerify(nodeAlgo);
|
|
10639
|
-
verifier.update(signedInfoNode.rawOuterXml);
|
|
10640
10662
|
try {
|
|
10641
|
-
|
|
10663
|
+
const hashName = nodeAlgo === "RSA-SHA1" ? "SHA-1" : "SHA-256";
|
|
10664
|
+
const certDer = pemToArrayBuffer(normalizedCert);
|
|
10665
|
+
const cryptoKey = await globalThis.crypto.subtle.importKey(
|
|
10666
|
+
"spki",
|
|
10667
|
+
certDer,
|
|
10668
|
+
{ name: "RSASSA-PKCS1-v1_5", hash: hashName },
|
|
10669
|
+
false,
|
|
10670
|
+
["verify"]
|
|
10671
|
+
);
|
|
10672
|
+
const signatureBuffer = base64ToArrayBuffer(sigValue);
|
|
10673
|
+
const dataBuffer = new TextEncoder().encode(signedInfoNode.rawOuterXml);
|
|
10674
|
+
return await globalThis.crypto.subtle.verify(
|
|
10675
|
+
"RSASSA-PKCS1-v1_5",
|
|
10676
|
+
cryptoKey,
|
|
10677
|
+
signatureBuffer,
|
|
10678
|
+
dataBuffer
|
|
10679
|
+
);
|
|
10642
10680
|
} catch {
|
|
10643
10681
|
return false;
|
|
10644
10682
|
}
|
|
@@ -10655,7 +10693,7 @@ function removeSignatureFromXml(xml) {
|
|
|
10655
10693
|
}
|
|
10656
10694
|
return result;
|
|
10657
10695
|
}
|
|
10658
|
-
function parseSamlResponse(samlResponse, provider, expectedRequestId) {
|
|
10696
|
+
async function parseSamlResponse(samlResponse, provider, expectedRequestId) {
|
|
10659
10697
|
const decoded = atob(samlResponse);
|
|
10660
10698
|
let doc;
|
|
10661
10699
|
try {
|
|
@@ -10683,7 +10721,7 @@ function parseSamlResponse(samlResponse, provider, expectedRequestId) {
|
|
|
10683
10721
|
"SAML response is not signed but signature is required"
|
|
10684
10722
|
);
|
|
10685
10723
|
}
|
|
10686
|
-
if (!verifySamlSignature(doc, provider.cert)) {
|
|
10724
|
+
if (!await verifySamlSignature(doc, provider.cert)) {
|
|
10687
10725
|
throw new SsoError(
|
|
10688
10726
|
SSO_ERROR.SAML_SIGNATURE_INVALID,
|
|
10689
10727
|
"SAML response signature verification failed"
|
|
@@ -10839,20 +10877,22 @@ var RateLimiter = class {
|
|
|
10839
10877
|
}
|
|
10840
10878
|
}
|
|
10841
10879
|
};
|
|
10842
|
-
function encodeState(stateTtlSeconds) {
|
|
10880
|
+
async function encodeState(stateTtlSeconds) {
|
|
10843
10881
|
const now = Date.now();
|
|
10844
10882
|
const expires = now + stateTtlSeconds * 1e3;
|
|
10845
|
-
const random =
|
|
10883
|
+
const random = randomBytesHex(16);
|
|
10846
10884
|
const payload = `${random}.${expires}`;
|
|
10847
|
-
const
|
|
10885
|
+
const hashBytes = await sha256Raw(payload);
|
|
10886
|
+
const hash = toHex(hashBytes).slice(0, 8);
|
|
10848
10887
|
return `${payload}.${hash}`;
|
|
10849
10888
|
}
|
|
10850
|
-
function validateStateToken(state) {
|
|
10889
|
+
async function validateStateToken(state) {
|
|
10851
10890
|
const parts = state.split(".");
|
|
10852
10891
|
if (parts.length !== 3) return false;
|
|
10853
10892
|
const [random, expiresStr, hash] = parts;
|
|
10854
10893
|
const payload = `${random}.${expiresStr}`;
|
|
10855
|
-
const
|
|
10894
|
+
const hashBytes = await sha256Raw(payload);
|
|
10895
|
+
const expectedHash = toHex(hashBytes).slice(0, 8);
|
|
10856
10896
|
if (hash !== expectedHash) return false;
|
|
10857
10897
|
const expires = Number.parseInt(expiresStr, 10);
|
|
10858
10898
|
if (Number.isNaN(expires)) return false;
|
|
@@ -10887,7 +10927,7 @@ function createSsoModule(config, db) {
|
|
|
10887
10927
|
auditLog({ ...event, timestamp: /* @__PURE__ */ new Date() });
|
|
10888
10928
|
}
|
|
10889
10929
|
async function createConnection(input) {
|
|
10890
|
-
const id = `sso_${
|
|
10930
|
+
const id = `sso_${generateId().replace(/-/g, "")}`;
|
|
10891
10931
|
const now = /* @__PURE__ */ new Date();
|
|
10892
10932
|
await db.insert(ssoConnections).values({
|
|
10893
10933
|
id,
|
|
@@ -10980,8 +11020,9 @@ function createSsoModule(config, db) {
|
|
|
10980
11020
|
`SAML provider "${conn.providerId}" not configured`
|
|
10981
11021
|
);
|
|
10982
11022
|
try {
|
|
10983
|
-
const { email, name } = parseSamlResponse(samlResponse, provider, expectedRequestId);
|
|
10984
|
-
const
|
|
11023
|
+
const { email, name } = await parseSamlResponse(samlResponse, provider, expectedRequestId);
|
|
11024
|
+
const userIdHash = await sha256Raw(`${conn.providerId}:${email}`);
|
|
11025
|
+
const userId = `saml_${toHex(userIdHash).slice(0, 32)}`;
|
|
10985
11026
|
emitAudit({
|
|
10986
11027
|
type: "sso_login_success",
|
|
10987
11028
|
connectionId,
|
|
@@ -11114,8 +11155,8 @@ function createSsoModule(config, db) {
|
|
|
11114
11155
|
}
|
|
11115
11156
|
if (payload.at_hash && tokens.access_token) {
|
|
11116
11157
|
const atHash = payload.at_hash;
|
|
11117
|
-
const
|
|
11118
|
-
const leftHalf =
|
|
11158
|
+
const accessTokenHashBytes = await sha256Raw(tokens.access_token);
|
|
11159
|
+
const leftHalf = accessTokenHashBytes.subarray(0, accessTokenHashBytes.length / 2);
|
|
11119
11160
|
const expectedAtHash = uint8ArrayToBase64Url(leftHalf);
|
|
11120
11161
|
if (atHash !== expectedAtHash) {
|
|
11121
11162
|
emitAudit({
|
|
@@ -11134,7 +11175,8 @@ function createSsoModule(config, db) {
|
|
|
11134
11175
|
);
|
|
11135
11176
|
}
|
|
11136
11177
|
const name = payload.name ?? void 0;
|
|
11137
|
-
const
|
|
11178
|
+
const oidcUserIdHash = await sha256Raw(`${conn.providerId}:${payload.sub}`);
|
|
11179
|
+
const userId = `oidc_${toHex(oidcUserIdHash).slice(0, 32)}`;
|
|
11138
11180
|
emitAudit({
|
|
11139
11181
|
type: "sso_login_success",
|
|
11140
11182
|
connectionId,
|
|
@@ -11146,10 +11188,10 @@ function createSsoModule(config, db) {
|
|
|
11146
11188
|
orgId: conn.orgId
|
|
11147
11189
|
};
|
|
11148
11190
|
}
|
|
11149
|
-
function generateState() {
|
|
11191
|
+
async function generateState() {
|
|
11150
11192
|
return encodeState(stateTtlSeconds);
|
|
11151
11193
|
}
|
|
11152
|
-
function validateState(state) {
|
|
11194
|
+
async function validateState(state) {
|
|
11153
11195
|
return validateStateToken(state);
|
|
11154
11196
|
}
|
|
11155
11197
|
async function handleRequest(request) {
|
|
@@ -12512,5 +12554,5 @@ function createWebhookModule(configs) {
|
|
|
12512
12554
|
}
|
|
12513
12555
|
|
|
12514
12556
|
export { EVENT_TYPES, HibpApiError, HibpBreachedError, OAuthProxyError, OneTapVerifyError, SSO_ERROR, SsoError, additionalFields, admin, anonymousAuth, apiKeys2 as apiKeys, bearerAuth, createAdditionalFieldsModule, createAdminModule, createAnonymousAuthModule, createApiKeyManagerModule, createCaptchaModule, createCostAttributionModule, createCustomSessionModule, createDeviceAuthModule, createEmailOtpModule, createEmailVerificationModule, createEphemeralSessionModule, createEventStreamModule, createFederationModule, createGdprModule, createHibpModule, createJwtSessionModule, createLastLoginModule, createMagicLinkModule, createOAuthProxyModule, createOidcProviderModule, createOneTapModule, createOneTimeTokenModule, createOpenApiModule, createOrgModule, createPasskeyModule, createPasswordResetModule, createPhoneAuthModule, createPolarModule, createRateLimiter, createReBACModule, createScimModule, createSessionManager, createSiweModule, createSsoModule, createStripeModule, createTotpModule, createTrustedDeviceModule, createUsernameAuthModule, createWebhookModule, customAuth, customSession, deviceAuth, deviceLabelFromRequest, emailOtp, gdpr, headerAuth, magicLink, oauthProxy, oneTap, organization, passkey, polar, scim, siwe, stripe, twoFactor, withRateLimit };
|
|
12515
|
-
//# sourceMappingURL=chunk-
|
|
12516
|
-
//# sourceMappingURL=chunk-
|
|
12557
|
+
//# sourceMappingURL=chunk-IEOOSOJ4.js.map
|
|
12558
|
+
//# sourceMappingURL=chunk-IEOOSOJ4.js.map
|