@korajs/auth 0.4.0 → 0.5.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 CHANGED
@@ -17,6 +17,23 @@ Offline-first authentication for Kora.js applications.
17
17
  - **Passkeys (WebAuthn)** -- passwordless authentication with platform authenticators
18
18
  - **Encrypted token storage** -- AES-256-GCM encryption for sensitive environments
19
19
  - **End-to-end encryption** -- encrypt operation data before sync with `OperationEncryptor`
20
+ - **Sync auth binding** -- `createKoraAuthSync()` wires tokens, JWT scopes, and device node ids to `createApp`
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
+ ```typescript
27
+ import { createKoraAuth } from '@korajs/auth'
28
+
29
+ const authClient = createKoraAuth({
30
+ serverUrl: 'https://acme.example.com',
31
+ credentialStore: secureStore,
32
+ deviceKeyStore,
33
+ })
34
+ ```
35
+
36
+ `createKoraAuth()` uses IndexedDB for the device key pair when available. React Native and other runtimes without IndexedDB should pass a platform-backed `deviceKeyStore`.
20
37
 
21
38
  ## Installation
22
39
 
@@ -29,10 +46,10 @@ pnpm add @korajs/auth
29
46
  ### Client-side (React)
30
47
 
31
48
  ```tsx
32
- import { AuthClient } from '@korajs/auth'
49
+ import { createKoraAuth } from '@korajs/auth'
33
50
  import { AuthProvider, useAuth } from '@korajs/auth/react'
34
51
 
35
- const authClient = new AuthClient({ serverUrl: 'http://localhost:3001' })
52
+ const authClient = createKoraAuth({ serverUrl: 'http://localhost:3001' })
36
53
 
37
54
  function App() {
38
55
  return (
@@ -43,15 +60,20 @@ function App() {
43
60
  }
44
61
 
45
62
  function MyApp() {
46
- const { user, isAuthenticated, isLoading, signIn, signOut, error } = useAuth()
63
+ const { user, isAuthenticated, isLoading, signIn, signInWithOAuth, signOut, error } = useAuth()
47
64
 
48
65
  if (isLoading) return <div>Loading...</div>
49
66
 
50
67
  if (!isAuthenticated) {
51
68
  return (
52
- <button onClick={() => signIn({ email: 'user@example.com', password: 'password' })}>
53
- Sign In
54
- </button>
69
+ <>
70
+ <button onClick={() => signIn({ email: 'user@example.com', password: 'password' })}>
71
+ Sign In
72
+ </button>
73
+ <button onClick={() => signInWithOAuth('google')}>
74
+ Sign In with Google
75
+ </button>
76
+ </>
55
77
  )
56
78
  }
57
79
 
@@ -64,41 +86,66 @@ function MyApp() {
64
86
  }
65
87
  ```
66
88
 
67
- ### Server-side
68
-
69
- ```typescript
70
- import { BuiltInAuthRoutes, InMemoryUserStore, TokenManager } from '@korajs/auth/server'
71
-
72
- const userStore = new InMemoryUserStore()
73
- const tokenManager = new TokenManager({ secret: process.env.AUTH_SECRET! })
74
- const authRoutes = new BuiltInAuthRoutes({ userStore, tokenManager })
89
+ ### Sync integration
75
90
 
76
- // Wire into your HTTP server:
77
- app.post('/auth/signup', async (req, res) => {
78
- const result = await authRoutes.handleSignUp(req.body)
79
- res.status(result.status).json(result.body)
91
+ ```tsx
92
+ import { createKoraAuthSync } from '@korajs/auth'
93
+ import { createApp } from 'korajs'
94
+
95
+ const app = createApp({
96
+ schema,
97
+ sync: {
98
+ url: 'ws://localhost:3001/kora-sync',
99
+ authClient: createKoraAuthSync({ authClient, schema }),
100
+ },
80
101
  })
102
+ ```
81
103
 
82
- app.post('/auth/signin', async (req, res) => {
83
- const result = await authRoutes.handleSignIn(req.body)
84
- res.status(result.status).json(result.body)
104
+ ### Server-side
105
+
106
+ ```typescript
107
+ import {
108
+ createKoraAuthServer,
109
+ createSqliteOAuthStores,
110
+ googleProvider,
111
+ } from '@korajs/auth/server'
112
+
113
+ const oauthStores = await createSqliteOAuthStores({
114
+ filename: './auth.db',
85
115
  })
86
116
 
87
- app.post('/auth/refresh', async (req, res) => {
88
- const result = await authRoutes.handleRefresh(req.body)
89
- res.status(result.status).json(result.body)
117
+ const auth = createKoraAuthServer({
118
+ jwtSecret: process.env.KORA_AUTH_SECRET!,
119
+ oauth: {
120
+ providers: [
121
+ googleProvider({
122
+ clientId: process.env.GOOGLE_CLIENT_ID!,
123
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
124
+ redirectUri: 'https://app.example.com/auth/oauth/google/callback',
125
+ }),
126
+ ],
127
+ stateStore: oauthStores.stateStore,
128
+ linkedIdentityStore: oauthStores.linkedIdentityStore,
129
+ },
90
130
  })
91
131
 
92
- app.get('/auth/me', async (req, res) => {
93
- const token = req.headers.authorization?.replace('Bearer ', '') ?? ''
94
- const result = await authRoutes.handleGetMe(token)
132
+ // Wire into your HTTP server:
133
+ app.all('/auth/*', async (req, res) => {
134
+ const result = await auth.handleRequest({
135
+ method: req.method,
136
+ path: req.path,
137
+ body: req.body,
138
+ headers: req.headers,
139
+ query: req.query,
140
+ ip: req.ip,
141
+ })
95
142
  res.status(result.status).json(result.body)
96
143
  })
97
144
 
98
145
  // Bridge to Kora sync server:
99
146
  const syncServer = new KoraSyncServer({
100
147
  store,
101
- auth: authRoutes.toSyncAuthProvider(),
148
+ auth: auth.auth,
102
149
  })
103
150
  ```
104
151
 
@@ -108,6 +155,8 @@ const syncServer = new KoraSyncServer({
108
155
 
109
156
  | Export | Description |
110
157
  |--------|-------------|
158
+ | `createKoraAuth` | Quickstart client factory with storage and device identity defaults |
159
+ | `createKoraAuthSync` | Sync auth binding for `createApp({ sync: { authClient } })` |
111
160
  | `AuthClient` | Client-side auth manager (sign-up, sign-in, sign-out, token refresh) |
112
161
  | `OrgClient` | Client-side organization management |
113
162
  | `TokenStore` | Client-side token persistence (localStorage) |
@@ -139,10 +188,14 @@ const syncServer = new KoraSyncServer({
139
188
 
140
189
  | Export | Description |
141
190
  |--------|-------------|
191
+ | `createKoraAuthServer` | Quickstart server factory with auth routes and sync provider |
142
192
  | `BuiltInAuthRoutes` | HTTP route handlers for all auth operations |
143
193
  | `TokenManager` | JWT issuing, validation, refresh rotation, revocation |
144
194
  | `InMemoryUserStore` | Dev/test user store |
145
195
  | `InMemoryTokenRevocationStore` | Dev/test token revocation store |
196
+ | `OAuthManager` / provider helpers | OAuth authorization code flow and provider configs |
197
+ | `InMemoryLinkedIdentityStore` | Dev/test OAuth account-linking store |
198
+ | `createSqliteOAuthStores` / `createPostgresOAuthStores` | Durable OAuth state and linked identity stores |
146
199
  | `SessionManager` / `InMemorySessionStore` | Server-side session management |
147
200
  | `TotpManager` / `InMemoryTotpStore` | TOTP MFA with recovery codes |
148
201
  | `OrgRoutes` / `InMemoryOrgStore` | Organization CRUD, invitations, member management |