dexie-cloud-addon 4.2.4 → 4.3.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/TODO-SOCIALAUTH.md +545 -0
- package/dexie-cloud-import.json +2 -1
- package/dist/modern/DexieCloudAPI.d.ts +4 -0
- package/dist/modern/DexieCloudOptions.d.ts +20 -0
- package/dist/modern/authentication/exchangeOAuthCode.d.ts +23 -0
- package/dist/modern/authentication/fetchAuthProviders.d.ts +14 -0
- package/dist/modern/authentication/handleOAuthCallback.d.ts +57 -0
- package/dist/modern/authentication/interactWithUser.d.ts +19 -0
- package/dist/modern/authentication/oauthLogin.d.ts +37 -0
- package/dist/modern/default-ui/AuthProviderButton.d.ts +21 -0
- package/dist/modern/default-ui/LoginDialog.d.ts +5 -2
- package/dist/modern/default-ui/ProviderSelectionDialog.d.ts +7 -0
- package/dist/modern/dexie-cloud-addon.js +719 -169
- package/dist/modern/dexie-cloud-addon.js.map +1 -1
- package/dist/modern/dexie-cloud-addon.min.js +1 -1
- package/dist/modern/dexie-cloud-addon.min.js.gz +0 -0
- package/dist/modern/dexie-cloud-addon.min.js.map +1 -1
- package/dist/modern/errors/OAuthError.d.ts +10 -0
- package/dist/modern/service-worker.js +720 -170
- package/dist/modern/service-worker.js.map +1 -1
- package/dist/modern/service-worker.min.js +1 -1
- package/dist/modern/service-worker.min.js.map +1 -1
- package/dist/modern/types/DXCUserInteraction.d.ts +24 -1
- package/dist/umd/dexie-cloud-addon.js +2181 -2444
- package/dist/umd/dexie-cloud-addon.js.gz +0 -0
- package/dist/umd/dexie-cloud-addon.js.map +1 -1
- package/dist/umd/dexie-cloud-addon.min.js +1 -1
- package/dist/umd/dexie-cloud-addon.min.js.gz +0 -0
- package/dist/umd/dexie-cloud-addon.min.js.map +1 -1
- package/dist/umd/service-worker.js +2029 -2292
- package/dist/umd/service-worker.js.map +1 -1
- package/dist/umd/service-worker.min.js +1 -1
- package/dist/umd/service-worker.min.js.map +1 -1
- package/oauth_flow.md +299 -0
- package/package.json +10 -7
package/oauth_flow.md
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# OAuth Authorization Code Flow for Dexie Cloud SPA Integration
|
|
2
|
+
|
|
3
|
+
## Actors
|
|
4
|
+
|
|
5
|
+
- **SPA** – Customer's frontend application
|
|
6
|
+
- **Dexie Cloud** – Auth broker + database access control
|
|
7
|
+
- **OAuth Provider** – Google, GitHub, Apple, Microsoft, etc.
|
|
8
|
+
- **Popup Window** – Browser window initiated by the SPA
|
|
9
|
+
|
|
10
|
+
## Preconditions
|
|
11
|
+
|
|
12
|
+
The SPA:
|
|
13
|
+
|
|
14
|
+
- Generates a persistent public/private keypair
|
|
15
|
+
- Private key stored securely in IndexedDB
|
|
16
|
+
- Public key sent later during token exchange
|
|
17
|
+
- Needs two JWTs after login:
|
|
18
|
+
- Access Token (short-lived)
|
|
19
|
+
- Refresh Token (long-lived)
|
|
20
|
+
|
|
21
|
+
Dexie Cloud acts as OAuth broker and manages tenant + identity linkage.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Flow Overview
|
|
26
|
+
|
|
27
|
+
### 1. User Initiates Login
|
|
28
|
+
|
|
29
|
+
User clicks "Login", SPA displays list of providers:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Google | GitHub | Apple | Microsoft
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
No nonce or PKCE is created yet.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
### 2. User Selects Provider
|
|
40
|
+
|
|
41
|
+
Example: User selects **Google**
|
|
42
|
+
|
|
43
|
+
The client initiates the OAuth flow. There are three ways to do this:
|
|
44
|
+
|
|
45
|
+
#### 2a. Popup Flow (Recommended for Web SPAs)
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
popup = window.open('about:blank');
|
|
49
|
+
popup.location = `https://<db>.dexie.cloud/oauth/login/google?redirect_uri=${encodeURIComponent(window.location.origin)}`;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The `redirect_uri` parameter is used to determine the `targetOrigin` for postMessage.
|
|
53
|
+
|
|
54
|
+
#### 2b. Custom URL Scheme (Capacitor / Native Apps)
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
// Open in system browser or in-app browser
|
|
58
|
+
Browser.open({
|
|
59
|
+
url: `https://<db>.dexie.cloud/oauth/login/google?redirect_uri=${encodeURIComponent('myapp://oauth-callback')}`
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The custom scheme `myapp://` tells Dexie Cloud to redirect back via deep link.
|
|
64
|
+
|
|
65
|
+
#### 2c. Full Page Redirect (Web without Popup)
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
window.location.href = `https://<db>.dexie.cloud/oauth/login/google?redirect_uri=${encodeURIComponent('https://myapp.com/oauth-callback')}`;
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Used when popups are blocked or for a more traditional OAuth redirect flow.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### 3. Dexie Cloud Prepares OAuth
|
|
76
|
+
|
|
77
|
+
Dexie Cloud receives `/oauth/login/google` and generates:
|
|
78
|
+
|
|
79
|
+
- `state` (anti-CSRF)
|
|
80
|
+
- `code_verifier` (PKCE)
|
|
81
|
+
- `code_challenge` (PKCE)
|
|
82
|
+
|
|
83
|
+
Stores these in the challenges table, then redirects popup to provider:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
https://accounts.google.com/o/oauth2/v2/auth?
|
|
87
|
+
client_id=...
|
|
88
|
+
redirect_uri=https://<db>.dexie.cloud/oauth/callback/google
|
|
89
|
+
state=STATE
|
|
90
|
+
code_challenge=CHALLENGE
|
|
91
|
+
code_challenge_method=S256
|
|
92
|
+
response_type=code
|
|
93
|
+
scope=openid email profile
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Note: `redirect_uri` points to the **Dexie Cloud server** callback endpoint.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### 4. Provider Authenticates User
|
|
101
|
+
|
|
102
|
+
Provider authenticates the user and requests consent if needed.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### 5. Provider Callback to Dexie Cloud
|
|
107
|
+
|
|
108
|
+
Provider redirects back to popup:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
https://<db>.dexie.cloud/oauth/callback/google?code=CODE&state=STATE
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Dexie Cloud:
|
|
115
|
+
|
|
116
|
+
1. Verifies `state`
|
|
117
|
+
2. Performs token exchange with provider using PKCE
|
|
118
|
+
3. Extracts identity claims (email/id/name/…)
|
|
119
|
+
4. Verifies email is verified
|
|
120
|
+
5. Links identity to tenant/database
|
|
121
|
+
6. Generates a **single-use Dexie Cloud authorization code**
|
|
122
|
+
7. Deletes the OAuth state (one-time use)
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### 6. Dexie Cloud Delivers Auth Code to Client
|
|
127
|
+
|
|
128
|
+
Dexie Cloud returns HTML that delivers the authorization code back to the client.
|
|
129
|
+
The delivery method depends on how the client initiated the login:
|
|
130
|
+
|
|
131
|
+
#### 6a. Popup Flow (Web SPAs)
|
|
132
|
+
|
|
133
|
+
If `window.opener` exists, uses postMessage:
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
window.opener.postMessage(
|
|
137
|
+
{
|
|
138
|
+
type: 'dexie:oauthResult',
|
|
139
|
+
code: DEXIE_AUTH_CODE,
|
|
140
|
+
provider: 'google',
|
|
141
|
+
state: STATE
|
|
142
|
+
},
|
|
143
|
+
targetOrigin // Origin captured from redirect_uri or referer
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
window.close();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### 6b. Custom URL Scheme (Capacitor / Native Apps)
|
|
150
|
+
|
|
151
|
+
If the client passed a `redirect_uri` with a custom scheme (e.g., `myapp://oauth-callback`),
|
|
152
|
+
the callback page redirects to that URL:
|
|
153
|
+
|
|
154
|
+
```js
|
|
155
|
+
window.location.href =
|
|
156
|
+
'myapp://oauth-callback?code=DEXIE_AUTH_CODE&provider=google&state=STATE';
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The native app intercepts this deep link and extracts the parameters.
|
|
160
|
+
|
|
161
|
+
#### 6c. Full Page Redirect (Web without Popup)
|
|
162
|
+
|
|
163
|
+
If there's no `window.opener` but the client passed an http/https `redirect_uri`,
|
|
164
|
+
the callback page redirects back to the client URL:
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
window.location.href =
|
|
168
|
+
'https://myapp.com/oauth-callback?code=DEXIE_AUTH_CODE&provider=google&state=STATE';
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The client page at that URL handles the auth code from query parameters.
|
|
172
|
+
|
|
173
|
+
#### 6d. Error Case
|
|
174
|
+
|
|
175
|
+
If none of the above conditions are met (no opener, no redirect_uri), an error is displayed
|
|
176
|
+
explaining that the auth flow cannot complete.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
### 7. Client Receives Authorization Code
|
|
181
|
+
|
|
182
|
+
**For Popup Flow (6a):**
|
|
183
|
+
|
|
184
|
+
SPA listens for postMessage and verifies:
|
|
185
|
+
|
|
186
|
+
- `type === "dexie:oauthResult"`
|
|
187
|
+
- origin (implicit via postMessage)
|
|
188
|
+
- provider
|
|
189
|
+
- state (optional)
|
|
190
|
+
- popup lifecycle
|
|
191
|
+
|
|
192
|
+
**For Capacitor/Native Apps (6b):**
|
|
193
|
+
|
|
194
|
+
App registers a deep link handler for the custom URL scheme:
|
|
195
|
+
|
|
196
|
+
```js
|
|
197
|
+
// Capacitor example
|
|
198
|
+
App.addListener('appUrlOpen', ({ url }) => {
|
|
199
|
+
const params = new URL(url).searchParams;
|
|
200
|
+
const code = params.get('code');
|
|
201
|
+
const provider = params.get('provider');
|
|
202
|
+
const state = params.get('state');
|
|
203
|
+
// Proceed to token exchange
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**For Full Page Redirect (6c):**
|
|
208
|
+
|
|
209
|
+
Client page reads parameters from the URL:
|
|
210
|
+
|
|
211
|
+
```js
|
|
212
|
+
const params = new URLSearchParams(window.location.search);
|
|
213
|
+
const code = params.get('code');
|
|
214
|
+
const provider = params.get('provider');
|
|
215
|
+
const state = params.get('state');
|
|
216
|
+
// Proceed to token exchange
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Upon success, client proceeds to token exchange.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### 8. Client Performs Token Exchange
|
|
224
|
+
|
|
225
|
+
Client sends:
|
|
226
|
+
|
|
227
|
+
```http
|
|
228
|
+
POST /token
|
|
229
|
+
Content-Type: application/json
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Payload:
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"grant_type": "authorization_code",
|
|
237
|
+
"code": "<DEXIE_AUTH_CODE>",
|
|
238
|
+
"public_key": "<SPA_PUBLIC_KEY>",
|
|
239
|
+
"scopes": ["ACCESS_DB"]
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Dexie Cloud validates:
|
|
244
|
+
|
|
245
|
+
- Dexie authorization code integrity
|
|
246
|
+
- TTL (5 minutes)
|
|
247
|
+
- Single-use constraint
|
|
248
|
+
- Database context
|
|
249
|
+
- User identity and claims from stored data
|
|
250
|
+
- Subscription/license status
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### 9. Dexie Cloud Issues Tokens
|
|
255
|
+
|
|
256
|
+
Dexie Cloud responds with:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"access_token": "...",
|
|
261
|
+
"refresh_token": "...",
|
|
262
|
+
"expires_in": 3600,
|
|
263
|
+
"token_type": "Bearer"
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
This completes authentication.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Security Properties Achieved
|
|
272
|
+
|
|
273
|
+
- 🛑 No JWTs exposed via popup or URL
|
|
274
|
+
- 🛑 No refresh tokens in postMessage
|
|
275
|
+
- 🛑 Provider tokens never reach SPA (only Dexie tokens)
|
|
276
|
+
- 🛡 Single-use Dexie authorization code (5 min TTL)
|
|
277
|
+
- 🛡 PKCE prevents provider code interception
|
|
278
|
+
- 🛡 State stored server-side with TTL (30 min)
|
|
279
|
+
- 🛡 CSRF protection via `state` parameter
|
|
280
|
+
- 🛡 OAuth state deleted after use
|
|
281
|
+
- 🛡 Dexie auth code deleted after use
|
|
282
|
+
- 🛡 Email verification enforced by server
|
|
283
|
+
- 🛡 All provider exchanges happen server-side
|
|
284
|
+
- 🛡 CORS + origin protections during `/token` exchange
|
|
285
|
+
- 🛡 Future PoP (Proof-of-Possession) enabled via SPA public key
|
|
286
|
+
- 🛡 Works with Apple, Google, Microsoft, GitHub
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Resulting Benefits
|
|
291
|
+
|
|
292
|
+
- Works for SPA / PWA / Capacitor / WebViews
|
|
293
|
+
- Supports multi-tenant architectures
|
|
294
|
+
- Supports native account linking
|
|
295
|
+
- Enables refresh token rotation
|
|
296
|
+
- Supports offline-first/local-first model
|
|
297
|
+
|
|
298
|
+
This aligns with modern OIDC/OAuth best practices (2023+) and matches architectures used by:
|
|
299
|
+
Auth0, Firebase, Supabase, Okta, MSAL, Google Identity Services, Clerk, etc.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dexie-cloud-addon",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "Dexie addon that syncs with to Dexie Cloud",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "dist/modern/dexie-cloud-addon.min.js",
|
|
@@ -67,11 +67,11 @@
|
|
|
67
67
|
"author": "david.fahlander@gmail.com",
|
|
68
68
|
"license": "Apache-2.0",
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@rollup/plugin-commonjs": "^
|
|
71
|
-
"@rollup/plugin-node-resolve": "^
|
|
70
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
71
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
72
72
|
"@rollup/plugin-replace": "^5.0.4",
|
|
73
73
|
"@rollup/plugin-terser": "^0.4.4",
|
|
74
|
-
"@rollup/plugin-typescript": "^
|
|
74
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
75
75
|
"@types/node": "^18.11.18",
|
|
76
76
|
"dreambase-library": "^1.0.26",
|
|
77
77
|
"just-build": "*",
|
|
@@ -79,9 +79,12 @@
|
|
|
79
79
|
"karma-chrome-launcher": "*",
|
|
80
80
|
"karma-firefox-launcher": "*",
|
|
81
81
|
"karma-qunit": "*",
|
|
82
|
+
"karma-webdriver-launcher": "*",
|
|
83
|
+
"qunit": "2.10.0",
|
|
84
|
+
"qunitjs": "1.23.1",
|
|
82
85
|
"lib0": "^0.2.97",
|
|
83
86
|
"preact": "*",
|
|
84
|
-
"rollup": "^4.
|
|
87
|
+
"rollup": "^4.53.3",
|
|
85
88
|
"terser": "^5.20.0",
|
|
86
89
|
"tslib": "*",
|
|
87
90
|
"typescript": "^5.6.3",
|
|
@@ -92,10 +95,10 @@
|
|
|
92
95
|
"yjs": "^13.6.27",
|
|
93
96
|
"y-protocols": "^1.0.6",
|
|
94
97
|
"y-dexie": "^4.2.2",
|
|
95
|
-
"dexie-cloud-common": "^1.0.
|
|
98
|
+
"dexie-cloud-common": "^1.0.57"
|
|
96
99
|
},
|
|
97
100
|
"peerDependencies": {
|
|
98
|
-
"dexie": "^4.
|
|
101
|
+
"dexie": "^4.3.0"
|
|
99
102
|
},
|
|
100
103
|
"scripts": {
|
|
101
104
|
"test": "just-build test && pnpm run test-unit",
|