@korajs/auth 0.0.0-canary-20261008174129
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/LICENSE +21 -0
- package/README.md +253 -0
- package/dist/chunk-IO2MCCG2.js +781 -0
- package/dist/chunk-IO2MCCG2.js.map +1 -0
- package/dist/chunk-L7GXPS74.js +46 -0
- package/dist/chunk-L7GXPS74.js.map +1 -0
- package/dist/chunk-MPMXJ62R.js +203 -0
- package/dist/chunk-MPMXJ62R.js.map +1 -0
- package/dist/create-org-session-ChFdulEM.d.cts +916 -0
- package/dist/create-org-session-ChFdulEM.d.ts +916 -0
- package/dist/index.cjs +3335 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +753 -0
- package/dist/index.d.ts +753 -0
- package/dist/index.js +2377 -0
- package/dist/index.js.map +1 -0
- package/dist/operation-encryptor-DDdlb9bm.d.cts +409 -0
- package/dist/operation-encryptor-DDdlb9bm.d.ts +409 -0
- package/dist/password-hash-QRBG6BNJ.js +9 -0
- package/dist/password-hash-QRBG6BNJ.js.map +1 -0
- package/dist/react.cjs +532 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +110 -0
- package/dist/react.d.ts +110 -0
- package/dist/react.js +316 -0
- package/dist/react.js.map +1 -0
- package/dist/server.cjs +8280 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +4843 -0
- package/dist/server.d.ts +4843 -0
- package/dist/server.js +7548 -0
- package/dist/server.js.map +1 -0
- package/dist/svelte.cjs +512 -0
- package/dist/svelte.cjs.map +1 -0
- package/dist/svelte.d.cts +100 -0
- package/dist/svelte.d.ts +100 -0
- package/dist/svelte.js +278 -0
- package/dist/svelte.js.map +1 -0
- package/dist/vue.cjs +565 -0
- package/dist/vue.cjs.map +1 -0
- package/dist/vue.d.cts +136 -0
- package/dist/vue.d.ts +136 -0
- package/dist/vue.js +338 -0
- package/dist/vue.js.map +1 -0
- package/package.json +118 -0
- package/src/admin/admin-api.ts +327 -0
- package/src/admin/audit-log.ts +324 -0
- package/src/admin/webhooks.ts +576 -0
- package/src/bindings/create-auth-session.ts +184 -0
- package/src/bindings/create-org-session.ts +130 -0
- package/src/client/auth-client.ts +1592 -0
- package/src/client/auth-sync.ts +213 -0
- package/src/client/device-session.ts +104 -0
- package/src/client/org-client.ts +399 -0
- package/src/client/quickstart.ts +108 -0
- package/src/client/storage.ts +94 -0
- package/src/device/device-identity.ts +330 -0
- package/src/device/device-store.ts +379 -0
- package/src/encryption/auto-lock.ts +170 -0
- package/src/encryption/database-encryption.ts +265 -0
- package/src/encryption/key-derivation.ts +149 -0
- package/src/encryption/operation-encryptor.ts +361 -0
- package/src/index.ts +132 -0
- package/src/mfa/totp.ts +826 -0
- package/src/org/org-routes.ts +758 -0
- package/src/org/org-store.ts +490 -0
- package/src/org/org-types.ts +230 -0
- package/src/passkey/passkey-client.ts +597 -0
- package/src/passkey/passkey-server.ts +779 -0
- package/src/postgres/ensure-schema.ts +65 -0
- package/src/provider/adapter.ts +246 -0
- package/src/provider/built-in/auth-routes.ts +1313 -0
- package/src/provider/built-in/email-verification.ts +303 -0
- package/src/provider/built-in/password-hash.ts +118 -0
- package/src/provider/built-in/password-reset.ts +416 -0
- package/src/provider/built-in/postgres-user-store.ts +365 -0
- package/src/provider/built-in/quickstart-server.ts +760 -0
- package/src/provider/built-in/sqlite-user-store.ts +335 -0
- package/src/provider/built-in/sync-scopes.ts +85 -0
- package/src/provider/built-in/user-store.ts +465 -0
- package/src/provider/external/clerk-adapter.ts +157 -0
- package/src/provider/external/external-jwt-provider.ts +491 -0
- package/src/provider/external/supabase-adapter.ts +163 -0
- package/src/provider/oauth/linked-identity-store.ts +108 -0
- package/src/provider/oauth/oauth-flow.ts +550 -0
- package/src/provider/oauth/oauth-types.ts +184 -0
- package/src/provider/oauth/postgres-oauth-store.ts +296 -0
- package/src/provider/oauth/sqlite-oauth-store.ts +285 -0
- package/src/rbac/rbac-engine.ts +323 -0
- package/src/rbac/rbac-types.ts +210 -0
- package/src/rbac/scope-resolver.ts +140 -0
- package/src/react/AuthProvider.tsx +97 -0
- package/src/react/OrgProvider.tsx +41 -0
- package/src/react/auth-context.ts +26 -0
- package/src/react/hooks.ts +110 -0
- package/src/react/org-hooks.ts +214 -0
- package/src/react.ts +26 -0
- package/src/server.ts +338 -0
- package/src/session/session.ts +401 -0
- package/src/svelte/AuthProvider.svelte +37 -0
- package/src/svelte/OrgProvider.svelte +22 -0
- package/src/svelte/auth-context.ts +50 -0
- package/src/svelte/org-context.ts +32 -0
- package/src/svelte/org-hooks.ts +201 -0
- package/src/svelte/use-auth.ts +115 -0
- package/src/svelte.ts +25 -0
- package/src/tokens/encrypted-token-store.ts +360 -0
- package/src/tokens/jwt.ts +236 -0
- package/src/tokens/postgres-token-revocation-store.ts +140 -0
- package/src/tokens/sqlite-token-revocation-store.ts +121 -0
- package/src/tokens/token-manager.ts +821 -0
- package/src/tokens/token-store.ts +192 -0
- package/src/types.ts +394 -0
- package/src/vue/auth-context.ts +10 -0
- package/src/vue/auth-provider-types.ts +5 -0
- package/src/vue/auth-provider.ts +76 -0
- package/src/vue/org-hooks.ts +193 -0
- package/src/vue/org-provider.ts +49 -0
- package/src/vue/use-auth.ts +139 -0
- package/src/vue.ts +10 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dr. Obed Ehoneah
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# @korajs/auth
|
|
2
|
+
|
|
3
|
+
Offline-first authentication for Kora.js applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`@korajs/auth` provides a complete authentication system designed for offline-first applications. It includes:
|
|
8
|
+
|
|
9
|
+
- **Client-side auth management**: token storage, session restoration, sign-up/sign-in/sign-out
|
|
10
|
+
- **React hooks**: `useAuth()`, `useCurrentUser()`, `useAuthStatus()`, `useOrg()`, `usePermission()`
|
|
11
|
+
- **Server-side auth routes**: email/password authentication with JWT tokens
|
|
12
|
+
- **Device identity**: ECDSA P-256 key pairs for proof-of-possession
|
|
13
|
+
- **Token management**: access/refresh token lifecycle with rotation and revocation detection
|
|
14
|
+
- **Session management**: server-side sessions with idle timeout, max limits, and MFA awareness
|
|
15
|
+
- **Multi-factor authentication**: TOTP (authenticator apps) with recovery codes
|
|
16
|
+
- **Organizations and RBAC**: multi-tenant orgs with role hierarchy and permission checks
|
|
17
|
+
- **Passkeys (WebAuthn)**: passwordless authentication with platform authenticators
|
|
18
|
+
- **Encrypted token storage**: AES-256-GCM encryption for sensitive environments
|
|
19
|
+
- **Local encryption helpers**: AES-256-GCM keys, PBKDF2 key derivation and auto-lock (end-to-end encryption of synced data is `sync.encryption` in `korajs`)
|
|
20
|
+
- **Sync auth binding**: `createKoraAuthSync()` binds sync to the signed-in user: per-user writes, token refresh, suspension while signed out, and scope hints
|
|
21
|
+
|
|
22
|
+
The client APIs work in browser, Tauri desktop WebView, and mobile JavaScript environments. For desktop apps, run auth routes on your remote sync/auth server and point `AuthClient.serverUrl` at that server. Email/password auth, token refresh, sync authorization, MFA, organizations, and RBAC work across web and desktop clients. Passkeys should be feature-detected because WebAuthn support depends on the operating system WebView.
|
|
23
|
+
|
|
24
|
+
For production desktop and mobile apps, pass a custom token storage adapter backed by the platform credential store and attach a stable device identity:
|
|
25
|
+
|
|
26
|
+
<!-- docs-check: standalone -->
|
|
27
|
+
```typescript
|
|
28
|
+
import { createKoraAuth, type AuthKeyValueStorage, type DeviceKeyStore } from '@korajs/auth'
|
|
29
|
+
|
|
30
|
+
declare const secureStore: AuthKeyValueStorage // Keychain, Keystore, a Tauri secure-storage plugin
|
|
31
|
+
declare const deviceKeyStore: DeviceKeyStore
|
|
32
|
+
|
|
33
|
+
const authClient = createKoraAuth({
|
|
34
|
+
serverUrl: 'https://acme.example.com',
|
|
35
|
+
credentialStore: secureStore,
|
|
36
|
+
deviceKeyStore,
|
|
37
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`createKoraAuth()` uses IndexedDB for the device key pair when available. React Native and other runtimes without IndexedDB should pass a platform-backed `deviceKeyStore`.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add @korajs/auth@beta
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
### Client-side (React)
|
|
51
|
+
|
|
52
|
+
<!-- docs-check: file auth-client.tsx -->
|
|
53
|
+
```tsx
|
|
54
|
+
import { createKoraAuth } from '@korajs/auth'
|
|
55
|
+
import { AuthProvider, useAuth } from '@korajs/auth/react'
|
|
56
|
+
|
|
57
|
+
export const authClient = createKoraAuth({ serverUrl: 'http://localhost:3001' })
|
|
58
|
+
|
|
59
|
+
export function App() {
|
|
60
|
+
return (
|
|
61
|
+
<AuthProvider client={authClient}>
|
|
62
|
+
<MyApp />
|
|
63
|
+
</AuthProvider>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function MyApp() {
|
|
68
|
+
const { user, isAuthenticated, isLoading, signIn, signInWithOAuth, signOut, error } = useAuth()
|
|
69
|
+
|
|
70
|
+
if (isLoading) return <div>Loading...</div>
|
|
71
|
+
|
|
72
|
+
if (!isAuthenticated) {
|
|
73
|
+
return (
|
|
74
|
+
<>
|
|
75
|
+
<button onClick={() => signIn({ email: 'user@example.com', password: 'password' })}>
|
|
76
|
+
Sign In
|
|
77
|
+
</button>
|
|
78
|
+
<button onClick={() => signInWithOAuth('google')}>
|
|
79
|
+
Sign In with Google
|
|
80
|
+
</button>
|
|
81
|
+
</>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<div>
|
|
87
|
+
<p>Welcome, {user?.name ?? user?.email}</p>
|
|
88
|
+
<button onClick={() => signOut()}>Sign Out</button>
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Sync integration
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { createKoraAuthSync } from '@korajs/auth'
|
|
98
|
+
import { createApp, defineSchema, t } from 'korajs'
|
|
99
|
+
import { authClient } from './auth-client'
|
|
100
|
+
|
|
101
|
+
const schema = defineSchema({ version: 1, collections: { todos: { fields: { title: t.string() } } } })
|
|
102
|
+
|
|
103
|
+
const app = createApp({
|
|
104
|
+
schema,
|
|
105
|
+
sync: {
|
|
106
|
+
url: 'ws://localhost:3001/kora-sync',
|
|
107
|
+
authClient: createKoraAuthSync({ authClient, schema }),
|
|
108
|
+
autoConnect: true,
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Sync waits while nobody is signed in (`anonymous: 'allow'` syncs anonymously instead), and every
|
|
114
|
+
local write belongs to the user who made it.
|
|
115
|
+
|
|
116
|
+
### Server-side
|
|
117
|
+
|
|
118
|
+
<!-- docs-check: standalone -->
|
|
119
|
+
```typescript
|
|
120
|
+
import {
|
|
121
|
+
createKoraAuthServer,
|
|
122
|
+
createSqliteOAuthStores,
|
|
123
|
+
createSqliteUserStore,
|
|
124
|
+
googleProvider,
|
|
125
|
+
} from '@korajs/auth/server'
|
|
126
|
+
import { createProductionServer, createSqliteServerStore } from '@korajs/server'
|
|
127
|
+
|
|
128
|
+
const userStore = await createSqliteUserStore({ filename: './auth.db' })
|
|
129
|
+
const oauthStores = await createSqliteOAuthStores({ filename: './auth.db' })
|
|
130
|
+
|
|
131
|
+
const auth = createKoraAuthServer({
|
|
132
|
+
jwtSecret: process.env.KORA_AUTH_SECRET, // required in production
|
|
133
|
+
userStore, // production refuses in-memory stores
|
|
134
|
+
oauth: {
|
|
135
|
+
providers: [
|
|
136
|
+
googleProvider({
|
|
137
|
+
clientId: process.env.GOOGLE_CLIENT_ID ?? '',
|
|
138
|
+
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
|
139
|
+
redirectUri: 'https://app.example.com/auth/oauth/google/callback',
|
|
140
|
+
}),
|
|
141
|
+
],
|
|
142
|
+
stateStore: oauthStores.stateStore,
|
|
143
|
+
linkedIdentityStore: oauthStores.linkedIdentityStore,
|
|
144
|
+
},
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
const server = createProductionServer({
|
|
148
|
+
store: createSqliteServerStore({ filename: './kora-server.db' }),
|
|
149
|
+
httpRoutes: [{ path: '/auth', handle: auth.handleRequest }],
|
|
150
|
+
syncOptions: { auth: auth.auth }, // verified identity and server-granted scopes
|
|
151
|
+
})
|
|
152
|
+
await server.start()
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Exports
|
|
156
|
+
|
|
157
|
+
### `@korajs/auth` (client entry)
|
|
158
|
+
|
|
159
|
+
| Export | Description |
|
|
160
|
+
|--------|-------------|
|
|
161
|
+
| `createKoraAuth` | Quickstart client factory with storage and device identity defaults |
|
|
162
|
+
| `createKoraAuthSync` | Sync auth binding for `createApp({ sync: { authClient } })` |
|
|
163
|
+
| `AuthClient` | Client-side auth manager (sign-up, sign-in, sign-out, token refresh) |
|
|
164
|
+
| `OrgClient` | Client-side organization management |
|
|
165
|
+
| `TokenStore` | Client-side token persistence (localStorage) |
|
|
166
|
+
| `EncryptedTokenStore` | AES-256-GCM encrypted token persistence |
|
|
167
|
+
| `generateDeviceKeyPair` | ECDSA P-256 key pair generation |
|
|
168
|
+
| `exportPublicKeyJwk` | Export public key as JWK |
|
|
169
|
+
| `signChallenge` / `verifyChallenge` | Device proof-of-possession |
|
|
170
|
+
| `computePublicKeyThumbprint` | RFC 7638 JWK thumbprint |
|
|
171
|
+
| `isPasskeySupported` | Check WebAuthn availability |
|
|
172
|
+
| `createPasskeyCredential` | Register a new passkey |
|
|
173
|
+
| `authenticateWithPasskey` | Sign in with a passkey |
|
|
174
|
+
| `encryptData` / `decryptData` | AES-256-GCM data encryption |
|
|
175
|
+
| `deriveEncryptionKey` / `generateEncryptionKey` | Local AES-256-GCM keys |
|
|
176
|
+
| `AutoLockManager` | Lock after an idle timeout |
|
|
177
|
+
|
|
178
|
+
### `@korajs/auth/react`
|
|
179
|
+
|
|
180
|
+
| Export | Description |
|
|
181
|
+
|--------|-------------|
|
|
182
|
+
| `AuthProvider` | React context provider |
|
|
183
|
+
| `useAuth` | Full auth hook (user, methods, error, loading) |
|
|
184
|
+
| `useCurrentUser` | Lightweight current user hook |
|
|
185
|
+
| `useAuthStatus` | Auth status for route guards |
|
|
186
|
+
| `useOrg` | Organization context and switching |
|
|
187
|
+
| `useOrgMembers` | Org member listing |
|
|
188
|
+
| `usePermission` | RBAC permission check hook |
|
|
189
|
+
|
|
190
|
+
### `@korajs/auth/server`
|
|
191
|
+
|
|
192
|
+
| Export | Description |
|
|
193
|
+
|--------|-------------|
|
|
194
|
+
| `createKoraAuthServer` | Quickstart server factory with auth routes and sync provider |
|
|
195
|
+
| `BuiltInAuthRoutes` | HTTP route handlers for all auth operations |
|
|
196
|
+
| `TokenManager` | JWT issuing, validation, refresh rotation, revocation |
|
|
197
|
+
| `createSqliteUserStore` / `createPostgresUserStore` | Durable users and token revocations |
|
|
198
|
+
| `InMemoryUserStore` | Dev/test user store |
|
|
199
|
+
| `OAuthManager` / provider helpers | OAuth authorization code flow and provider configs |
|
|
200
|
+
| `InMemoryLinkedIdentityStore` | Dev/test OAuth account-linking store |
|
|
201
|
+
| `createSqliteOAuthStores` / `createPostgresOAuthStores` | Durable OAuth state and linked identity stores |
|
|
202
|
+
| `SessionManager` / `InMemorySessionStore` | Server-side session management |
|
|
203
|
+
| `TotpManager` / `InMemoryTotpStore` | TOTP MFA with recovery codes |
|
|
204
|
+
| `OrgRoutes` / `InMemoryOrgStore` | Organization CRUD, invitations, member management |
|
|
205
|
+
| `RbacEngine` / `defineRoles` | Role-based access control with permission hierarchy |
|
|
206
|
+
| `OrgScopeResolver` | Generate sync scope filters from org membership |
|
|
207
|
+
| `EmailVerificationManager` | Email verification token flow |
|
|
208
|
+
| `PasswordResetManager` | Password reset and change flows |
|
|
209
|
+
| `hashPassword` / `verifyPassword` | PBKDF2-SHA512 password hashing |
|
|
210
|
+
| `encodeJwt` / `verifyJwt` | Low-level JWT operations |
|
|
211
|
+
|
|
212
|
+
## Security
|
|
213
|
+
|
|
214
|
+
- Passwords hashed with PBKDF2-SHA512 (600,000 iterations, 32-byte salt)
|
|
215
|
+
- JWT tokens signed with HMAC-SHA256 with constant-time comparison
|
|
216
|
+
- Atomic refresh token rotation with reuse detection per token family
|
|
217
|
+
- Device keys use ECDSA P-256 with non-extractable private keys (Web Crypto)
|
|
218
|
+
- TOTP uses SHA-1 HMAC per RFC 6238 with 30-second time steps
|
|
219
|
+
- Access tokens expire in 15 minutes and refresh tokens in 90 days (configurable)
|
|
220
|
+
- Revocation (sign-out, device, password change, admin) applies to every route and ends live sync sessions
|
|
221
|
+
- Sign-in is rate limited per account and per IP; MFA at sign-in with TOTP (replay protection and lockout)
|
|
222
|
+
- Session idle timeout with sliding window and configurable max concurrent sessions
|
|
223
|
+
- Passkeys use WebAuthn L2 with platform authenticator support
|
|
224
|
+
- The encrypted token store uses AES-256-GCM with a key you provide (generated or PBKDF2-derived)
|
|
225
|
+
|
|
226
|
+
## Architecture
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
Client Server
|
|
230
|
+
┌────────────────────┐ ┌────────────────────────┐
|
|
231
|
+
│ AuthClient │ │ BuiltInAuthRoutes │
|
|
232
|
+
│ ├─ TokenStore │ │ ├─ UserStore │
|
|
233
|
+
│ ├─ EncryptedStore │ ── HTTP ───> │ ├─ TokenManager │
|
|
234
|
+
│ ├─ OrgClient │ │ ├─ SessionManager │
|
|
235
|
+
│ └─ DeviceKeyStore │ │ ├─ TotpManager │
|
|
236
|
+
│ │ │ ├─ OrgRoutes │
|
|
237
|
+
│ React Hooks │ │ ├─ RbacEngine │
|
|
238
|
+
│ ├─ useAuth │ │ └─ PasswordResetMgr │
|
|
239
|
+
│ ├─ useOrg │ │ │
|
|
240
|
+
│ └─ usePermission │ │ SyncAuthProvider │
|
|
241
|
+
│ │ │ └─ authenticate() │
|
|
242
|
+
│ Passkeys │ │ └─ OrgScopeResolver │
|
|
243
|
+
│ └─ WebAuthn API │ └────────────────────────┘
|
|
244
|
+
└────────────────────┘
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Documentation
|
|
248
|
+
|
|
249
|
+
See the [Authentication Guide](https://korajs.dev/guide/authentication) and the [Auth API Reference](https://korajs.dev/api/auth).
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
MIT
|