dexie-cloud-addon 4.2.5 → 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/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 +577 -5
- 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 +577 -5
- 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/DISABLE_SERVICEWORKER_STRATEGY.d.ts +1 -0
- package/dist/umd/DXCWebSocketStatus.d.ts +1 -0
- package/dist/umd/DexieCloudAPI.d.ts +75 -0
- package/dist/umd/DexieCloudOptions.d.ts +27 -0
- package/dist/umd/DexieCloudSyncOptions.d.ts +4 -0
- package/dist/umd/DexieCloudTable.d.ts +18 -0
- package/dist/umd/InvalidLicenseError.d.ts +5 -0
- package/dist/umd/Invite.d.ts +8 -0
- package/dist/umd/PermissionChecker.d.ts +15 -0
- package/dist/umd/TSON.d.ts +17 -0
- package/dist/umd/WSObservable.d.ts +72 -0
- package/dist/umd/associate.d.ts +1 -0
- package/dist/umd/authentication/AuthPersistedContext.d.ts +9 -0
- package/dist/umd/authentication/TokenErrorResponseError.d.ts +10 -0
- package/dist/umd/authentication/TokenExpiredError.d.ts +3 -0
- package/dist/umd/authentication/UNAUTHORIZED_USER.d.ts +2 -0
- package/dist/umd/authentication/authenticate.d.ts +13 -0
- package/dist/umd/authentication/currentUserObservable.d.ts +1 -0
- package/dist/umd/authentication/interactWithUser.d.ts +21 -0
- package/dist/umd/authentication/login.d.ts +3 -0
- package/dist/umd/authentication/logout.d.ts +5 -0
- package/dist/umd/authentication/otpFetchTokenCallback.d.ts +3 -0
- package/dist/umd/authentication/setCurrentUser.d.ts +14 -0
- package/dist/umd/authentication/waitUntil.d.ts +3 -0
- package/dist/umd/computeSyncState.d.ts +4 -0
- package/dist/umd/createSharedValueObservable.d.ts +3 -0
- package/dist/umd/currentUserEmitter.d.ts +3 -0
- package/dist/umd/db/DexieCloudDB.d.ts +61 -0
- package/dist/umd/db/entities/BaseRevisionMapEntry.d.ts +5 -0
- package/dist/umd/db/entities/EntityCommon.d.ts +5 -0
- package/dist/umd/db/entities/GuardedJob.d.ts +5 -0
- package/dist/umd/db/entities/Member.d.ts +19 -0
- package/dist/umd/db/entities/PersistedSyncState.d.ts +22 -0
- package/dist/umd/db/entities/Realm.d.ts +14 -0
- package/dist/umd/db/entities/Role.d.ts +11 -0
- package/dist/umd/db/entities/UserLogin.d.ts +23 -0
- package/dist/umd/default-ui/Dialog.d.ts +5 -0
- package/dist/umd/default-ui/LoginDialog.d.ts +3 -0
- package/dist/umd/default-ui/Styles.d.ts +3 -0
- package/dist/umd/default-ui/index.d.ts +24 -0
- package/dist/umd/define-ydoc-trigger.d.ts +3 -0
- package/dist/umd/dexie-cloud-addon.d.ts +3 -0
- package/dist/umd/dexie-cloud-addon.js +578 -6
- 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/dexie-cloud-client.d.ts +23 -0
- package/dist/umd/errors/HttpError.d.ts +5 -0
- package/dist/umd/extend-dexie-interface.d.ts +23 -0
- package/dist/umd/getGlobalRolesObservable.d.ts +5 -0
- package/dist/umd/getInternalAccessControlObservable.d.ts +12 -0
- package/dist/umd/getInvitesObservable.d.ts +23 -0
- package/dist/umd/getPermissionsLookupObservable.d.ts +16 -0
- package/dist/umd/getTiedRealmId.d.ts +2 -0
- package/dist/umd/helpers/BroadcastedAndLocalEvent.d.ts +8 -0
- package/dist/umd/helpers/CancelToken.d.ts +4 -0
- package/dist/umd/helpers/IS_SERVICE_WORKER.d.ts +1 -0
- package/dist/umd/helpers/SWBroadcastChannel.d.ts +12 -0
- package/dist/umd/helpers/allSettled.d.ts +1 -0
- package/dist/umd/helpers/bulkUpdate.d.ts +4 -0
- package/dist/umd/helpers/computeRealmSetHash.d.ts +2 -0
- package/dist/umd/helpers/date-constants.d.ts +5 -0
- package/dist/umd/helpers/flatten.d.ts +1 -0
- package/dist/umd/helpers/getMutationTable.d.ts +1 -0
- package/dist/umd/helpers/getSyncableTables.d.ts +4 -0
- package/dist/umd/helpers/getTableFromMutationTable.d.ts +1 -0
- package/dist/umd/helpers/makeArray.d.ts +1 -0
- package/dist/umd/helpers/randomString.d.ts +1 -0
- package/dist/umd/helpers/resolveText.d.ts +16 -0
- package/dist/umd/helpers/throwVersionIncrementNeeded.d.ts +1 -0
- package/dist/umd/helpers/visibilityState.d.ts +1 -0
- package/dist/umd/isEagerSyncDisabled.d.ts +2 -0
- package/dist/umd/isFirefox.d.ts +1 -0
- package/dist/umd/isSafari.d.ts +2 -0
- package/dist/umd/mapValueObservable.d.ts +5 -0
- package/dist/umd/mergePermissions.d.ts +2 -0
- package/dist/umd/middleware-helpers/guardedTable.d.ts +11 -0
- package/dist/umd/middleware-helpers/idGenerationHelpers.d.ts +18 -0
- package/dist/umd/middlewares/createIdGenerationMiddleware.d.ts +3 -0
- package/dist/umd/middlewares/createImplicitPropSetterMiddleware.d.ts +3 -0
- package/dist/umd/middlewares/createMutationTrackingMiddleware.d.ts +17 -0
- package/dist/umd/middlewares/outstandingTransaction.d.ts +4 -0
- package/dist/umd/overrideParseStoresSpec.d.ts +4 -0
- package/dist/umd/performInitialSync.d.ts +4 -0
- package/dist/umd/permissions.d.ts +9 -0
- package/dist/umd/prodLog.d.ts +9 -0
- package/dist/umd/service-worker.d.ts +1 -0
- package/dist/umd/service-worker.js +578 -6
- 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/dist/umd/sync/DEXIE_CLOUD_SYNCER_ID.d.ts +1 -0
- package/dist/umd/sync/LocalSyncWorker.d.ts +7 -0
- package/dist/umd/sync/SyncRequiredError.d.ts +3 -0
- package/dist/umd/sync/applyServerChanges.d.ts +3 -0
- package/dist/umd/sync/connectWebSocket.d.ts +2 -0
- package/dist/umd/sync/encodeIdsForServer.d.ts +4 -0
- package/dist/umd/sync/extractRealm.d.ts +2 -0
- package/dist/umd/sync/getLatestRevisionsPerTable.d.ts +6 -0
- package/dist/umd/sync/getTablesToSyncify.d.ts +3 -0
- package/dist/umd/sync/isOnline.d.ts +1 -0
- package/dist/umd/sync/isSyncNeeded.d.ts +2 -0
- package/dist/umd/sync/listClientChanges.d.ts +9 -0
- package/dist/umd/sync/listSyncifiedChanges.d.ts +5 -0
- package/dist/umd/sync/messageConsumerIsReady.d.ts +2 -0
- package/dist/umd/sync/messagesFromServerQueue.d.ts +8 -0
- package/dist/umd/sync/modifyLocalObjectsWithNewUserId.d.ts +4 -0
- package/dist/umd/sync/myId.d.ts +1 -0
- package/dist/umd/sync/numUnsyncedMutations.d.ts +2 -0
- package/dist/umd/sync/old_startSyncingClientChanges.d.ts +39 -0
- package/dist/umd/sync/performGuardedJob.d.ts +2 -0
- package/dist/umd/sync/ratelimit.d.ts +3 -0
- package/dist/umd/sync/registerSyncEvent.d.ts +3 -0
- package/dist/umd/sync/sync.d.ts +15 -0
- package/dist/umd/sync/syncIfPossible.d.ts +5 -0
- package/dist/umd/sync/syncWithServer.d.ts +6 -0
- package/dist/umd/sync/triggerSync.d.ts +2 -0
- package/dist/umd/sync/updateBaseRevs.d.ts +5 -0
- package/dist/umd/types/DXCAlert.d.ts +25 -0
- package/dist/umd/types/DXCInputField.d.ts +11 -0
- package/dist/umd/types/DXCUserInteraction.d.ts +93 -0
- package/dist/umd/types/NewIdOptions.d.ts +3 -0
- package/dist/umd/types/SWMessageEvent.d.ts +3 -0
- package/dist/umd/types/SWSyncEvent.d.ts +4 -0
- package/dist/umd/types/SyncState.d.ts +9 -0
- package/dist/umd/types/TXExpandos.d.ts +11 -0
- package/dist/umd/updateSchemaFromOptions.d.ts +3 -0
- package/dist/umd/userIsActive.d.ts +7 -0
- package/dist/umd/verifyConfig.d.ts +2 -0
- package/dist/umd/verifySchema.d.ts +2 -0
- package/dist/umd/yjs/YDexieCloudSyncState.d.ts +3 -0
- package/dist/umd/yjs/YTable.d.ts +3 -0
- package/dist/umd/yjs/applyYMessages.d.ts +9 -0
- package/dist/umd/yjs/awareness.d.ts +3 -0
- package/dist/umd/yjs/createYClientUpdateObservable.d.ts +4 -0
- package/dist/umd/yjs/createYHandler.d.ts +2 -0
- package/dist/umd/yjs/downloadYDocsFromServer.d.ts +3 -0
- package/dist/umd/yjs/getUpdatesTable.d.ts +3 -0
- package/dist/umd/yjs/listUpdatesSince.d.ts +3 -0
- package/dist/umd/yjs/listYClientMessagesAndStateVector.d.ts +26 -0
- package/dist/umd/yjs/reopenDocSignal.d.ts +10 -0
- package/dist/umd/yjs/updateYSyncStates.d.ts +6 -0
- package/oauth_flow.md +299 -0
- package/package.json +3 -3
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
# Social Authentication for Dexie Cloud
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This feature adds support for OAuth 2.0 social login providers (Google, GitHub, Microsoft, Apple, and custom OAuth2) as an alternative to the existing OTP (One-Time Password) email authentication in Dexie Cloud.
|
|
6
|
+
|
|
7
|
+
**Key Design Principle**: The Dexie Cloud server acts as an OAuth broker, handling all provider interactions including the OAuth callback. The client library (dexie-cloud-addon) never receives provider tokens - only Dexie Cloud authorization codes which are exchanged for Dexie Cloud tokens.
|
|
8
|
+
|
|
9
|
+
### Related Files
|
|
10
|
+
|
|
11
|
+
- **Detailed flow diagram**: [oauth_flow.md](oauth_flow.md) - Sequence diagrams and detailed protocol description
|
|
12
|
+
- **Server implementation**: `/Users/daw/repos/dexie-cloud/libs/dexie-cloud-server`
|
|
13
|
+
- `src/api/oauth/registerOAuthEndpoints.ts` - OAuth endpoints
|
|
14
|
+
- `src/api/oauth/oauth-helpers.ts` - Provider exchange logic
|
|
15
|
+
- `src/api/registerTokenEndpoint.ts` - Token endpoint (authorization_code grant)
|
|
16
|
+
- `web-templates/oauth-callback.handlebars` - Callback page template
|
|
17
|
+
|
|
18
|
+
### Flow Summary
|
|
19
|
+
|
|
20
|
+
1. **Client** fetches available auth providers from `GET /auth-providers`
|
|
21
|
+
2. **Client** opens popup/redirect to `GET /oauth/login/:provider`
|
|
22
|
+
3. **Dexie Cloud Server** redirects to OAuth provider and handles callback at `/oauth/callback/:provider`
|
|
23
|
+
4. **Server** exchanges provider code for tokens, verifies email, generates single-use Dexie auth code
|
|
24
|
+
5. **Server** delivers auth code to client via postMessage (popup), custom URL scheme (Capacitor), or redirect
|
|
25
|
+
6. **Client** exchanges Dexie auth code for tokens via `POST /token` with `grant_type: "authorization_code"`
|
|
26
|
+
|
|
27
|
+
### Supported Providers
|
|
28
|
+
- **Google** - OpenID Connect with PKCE
|
|
29
|
+
- **GitHub** - OAuth 2.0 (client secret only)
|
|
30
|
+
- **Microsoft** - OpenID Connect with PKCE
|
|
31
|
+
- **Apple** - Sign in with Apple (form_post response mode)
|
|
32
|
+
- **Custom OAuth2** - Configurable endpoints for self-hosted identity providers
|
|
33
|
+
|
|
34
|
+
### Client Delivery Methods
|
|
35
|
+
|
|
36
|
+
The library must support multiple integration patterns:
|
|
37
|
+
|
|
38
|
+
| Method | Use Case | Delivery Mechanism |
|
|
39
|
+
|--------|----------|-------------------|
|
|
40
|
+
| **Popup** | Web SPAs (recommended) | `postMessage` with `type: 'dexie:oauthResult'` |
|
|
41
|
+
| **Custom URL Scheme** | Capacitor/Native apps | Deep link redirect (e.g., `myapp://oauth-callback`) |
|
|
42
|
+
| **Full Page Redirect** | Web without popup support | HTTP redirect with query params |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Server-Side Tasks (dexie-cloud-server)
|
|
47
|
+
|
|
48
|
+
### ✅ Completed
|
|
49
|
+
|
|
50
|
+
- [x] **OAuth provider configuration type** (`OAuthProviderConfig`)
|
|
51
|
+
- Supports `google`, `github`, `apple`, `microsoft`, `custom-oauth2`
|
|
52
|
+
- Configurable `clientId`, `clientSecret`, `scopes`, `enabled`
|
|
53
|
+
- Custom OAuth2 config for self-hosted providers (authorization/token/userinfo endpoints)
|
|
54
|
+
- `name` and `displayName` for custom providers
|
|
55
|
+
- `iconUrl` for custom provider icons
|
|
56
|
+
|
|
57
|
+
- [x] **`GET /auth-providers` endpoint**
|
|
58
|
+
- Returns list of enabled OAuth providers (without secrets) and OTP status
|
|
59
|
+
- Includes `type`, `name`, `displayName`, `iconUrl`, `scopes` per provider
|
|
60
|
+
- Default icons served from `/static/icons/` for built-in providers
|
|
61
|
+
|
|
62
|
+
- [x] **`GET /oauth/login/:provider` endpoint**
|
|
63
|
+
- Accepts `redirect_uri` parameter for postMessage target / deep link
|
|
64
|
+
- Validates `redirect_uri` against whitelisted origins (via `npx dexie-cloud whitelist`)
|
|
65
|
+
- Generates state and PKCE challenge
|
|
66
|
+
- Stores `state`, `codeVerifier`, `spaOrigin`, `clientRedirectUri` in challenges table
|
|
67
|
+
- Redirects to OAuth provider with server callback URL (`/oauth/callback/:provider`)
|
|
68
|
+
|
|
69
|
+
- [x] **`GET /oauth/callback/:provider` endpoint** (NEW)
|
|
70
|
+
- Receives callback from OAuth provider
|
|
71
|
+
- Verifies state against stored challenges
|
|
72
|
+
- Exchanges provider code for tokens (server-side)
|
|
73
|
+
- Fetches and verifies user info (email must be verified)
|
|
74
|
+
- Generates single-use Dexie Cloud authorization code (64 chars, 5 min TTL)
|
|
75
|
+
- Stores user claims with auth code in challenges table
|
|
76
|
+
- Returns HTML page that delivers auth code to client via:
|
|
77
|
+
- `postMessage` to `window.opener` (popup flow)
|
|
78
|
+
- Redirect to custom URL scheme (Capacitor/native)
|
|
79
|
+
- Redirect to HTTPS URL (full page redirect flow)
|
|
80
|
+
|
|
81
|
+
- [x] **`POST /token` with `grant_type: "authorization_code"`**
|
|
82
|
+
- Validates Dexie auth code (not provider code)
|
|
83
|
+
- Verifies code is `dexie_oauth` type and within 5 min TTL
|
|
84
|
+
- Extracts stored user claims (sub, email, name, picture, etc.)
|
|
85
|
+
- Generates Dexie Cloud access/refresh tokens
|
|
86
|
+
- `sub` format: `{provider}:{user_id}`
|
|
87
|
+
|
|
88
|
+
- [x] **OAuth helper functions** (`oauth-helpers.ts`)
|
|
89
|
+
- `getProviderEndpoints()` - Returns auth/token/userinfo URLs per provider
|
|
90
|
+
- `shouldUsePKCE()` - Determines if provider supports PKCE
|
|
91
|
+
- `exchangeCodeForTokens()` - Exchanges code for provider tokens
|
|
92
|
+
- `fetchUserInfo()` - Fetches and normalizes user info from provider
|
|
93
|
+
|
|
94
|
+
- [x] **Crypto utilities** (`crypto-utils.ts`)
|
|
95
|
+
- `generateRandomString()` - For state, PKCE code_verifier, and auth codes
|
|
96
|
+
|
|
97
|
+
- [x] **Handlebars template** (`oauth-callback.handlebars`)
|
|
98
|
+
- Renders callback page with postMessage/redirect logic
|
|
99
|
+
- Handles error display
|
|
100
|
+
|
|
101
|
+
- [x] **Configuration GUI in dexie-cloud-manager**
|
|
102
|
+
- `OAuthProviderDialog.tsx` - UI for configuring OAuth providers per database
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Client-Side Tasks (dexie-cloud-addon)
|
|
107
|
+
|
|
108
|
+
> **Note**: dexie-cloud-addon is a **library**, not an app. It must support various frameworks including Next.js, Vite, Svelte, SvelteKit, Capacitor, React Native, etc.
|
|
109
|
+
|
|
110
|
+
### Backward Compatibility Requirements
|
|
111
|
+
|
|
112
|
+
The implementation must be backward compatible in several scenarios:
|
|
113
|
+
|
|
114
|
+
#### 1. Apps with Custom Login GUI (not using default-ui)
|
|
115
|
+
|
|
116
|
+
Apps that implement their own login UI by subscribing to `db.cloud.userInteraction` must continue to work without changes. The new `DXCProviderSelection` type should only be emitted when:
|
|
117
|
+
- The server has OAuth providers configured AND enabled
|
|
118
|
+
- The client has NOT opted out via `db.cloud.configure({ socialAuth: false })`
|
|
119
|
+
|
|
120
|
+
**Solution**: Fetch `/auth-providers` first. If it returns providers, emit `DXCProviderSelection`. If empty or fails, emit `DXCEmailPrompt` as before. Apps with custom GUIs that don't handle `DXCProviderSelection` can:
|
|
121
|
+
- Add `socialAuth: false` to their config to disable it
|
|
122
|
+
- Or update their UI to handle the new type
|
|
123
|
+
|
|
124
|
+
#### 2. requireAuth with Unknown Server Capabilities
|
|
125
|
+
|
|
126
|
+
When `requireAuth: true`, the client must authenticate before accessing the database. The `/auth-providers` endpoint must be accessible **without authentication** (public read-only endpoint) so the client can discover available auth methods.
|
|
127
|
+
|
|
128
|
+
**Note**: The server already implements `/auth-providers` as a public endpoint (uses `readRateLimiter`, no auth required).
|
|
129
|
+
|
|
130
|
+
#### 3. On-Prem Customers with Older Server Versions
|
|
131
|
+
|
|
132
|
+
Customers running older dexie-cloud-server versions won't have the `/auth-providers` endpoint. The client must handle this gracefully:
|
|
133
|
+
|
|
134
|
+
**Solution**:
|
|
135
|
+
- Catch 404/network errors from `/auth-providers`
|
|
136
|
+
- Fall back to OTP-only flow (existing `DXCEmailPrompt` behavior)
|
|
137
|
+
- Never emit `DXCProviderSelection` if endpoint unavailable
|
|
138
|
+
- Log a debug message for troubleshooting
|
|
139
|
+
|
|
140
|
+
#### 4. Client Opt-Out
|
|
141
|
+
|
|
142
|
+
Even if the server has OAuth configured, apps may want to disable it client-side (e.g., during migration, or for specific deployments).
|
|
143
|
+
|
|
144
|
+
**Solution**: Add `socialAuth` option to `DexieCloudOptions`:
|
|
145
|
+
```typescript
|
|
146
|
+
interface DexieCloudOptions {
|
|
147
|
+
// ... existing options
|
|
148
|
+
|
|
149
|
+
/** Enable social/OAuth authentication.
|
|
150
|
+
* - true: Fetch providers from server, show if available (default)
|
|
151
|
+
* - false: Disable OAuth, always use OTP flow
|
|
152
|
+
*/
|
|
153
|
+
socialAuth?: boolean; // Default: true
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### ✅ Completed
|
|
158
|
+
|
|
159
|
+
#### Types in dexie-cloud-common
|
|
160
|
+
|
|
161
|
+
- [x] **Create `OAuthProviderInfo` type** (`libs/dexie-cloud-common/src/OAuthProviderInfo.ts`)
|
|
162
|
+
- [x] **Create `AuthProvidersResponse` type** (`libs/dexie-cloud-common/src/AuthProvidersResponse.ts`)
|
|
163
|
+
- [x] **Create `OAuthResultMessage` type** (`libs/dexie-cloud-common/src/OAuthResultMessage.ts`)
|
|
164
|
+
- [x] **Extend `TokenRequest` types** - Added `AuthorizationCodeTokenRequest` (`libs/dexie-cloud-common/src/AuthorizationCodeTokenRequest.ts`)
|
|
165
|
+
|
|
166
|
+
### 🔲 TODO
|
|
167
|
+
|
|
168
|
+
#### Types in dexie-cloud-common
|
|
169
|
+
|
|
170
|
+
> Types that reflect server API data should be placed in `dexie-cloud-common` (shared between server and client).
|
|
171
|
+
|
|
172
|
+
- [x] **Create `OAuthProviderInfo` type** (`libs/dexie-cloud-common`)
|
|
173
|
+
```typescript
|
|
174
|
+
interface OAuthProviderInfo {
|
|
175
|
+
type: 'google' | 'github' | 'microsoft' | 'apple' | 'custom-oauth2';
|
|
176
|
+
name: string; // Provider identifier (e.g., 'google' or custom name)
|
|
177
|
+
displayName: string; // Human-readable name
|
|
178
|
+
iconUrl?: string; // URL to provider icon
|
|
179
|
+
scopes?: string[];
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- [x] **Create `AuthProvidersResponse` type** (`libs/dexie-cloud-common`)
|
|
184
|
+
```typescript
|
|
185
|
+
interface AuthProvidersResponse {
|
|
186
|
+
providers: OAuthProviderInfo[];
|
|
187
|
+
otpEnabled: boolean;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- [x] **Create `OAuthResultMessage` type** (`libs/dexie-cloud-common`)
|
|
192
|
+
```typescript
|
|
193
|
+
interface OAuthResultMessage {
|
|
194
|
+
type: 'dexie:oauthResult';
|
|
195
|
+
code?: string; // Dexie auth code
|
|
196
|
+
error?: string; // Error message
|
|
197
|
+
provider: string;
|
|
198
|
+
state: string;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- [x] **Extend `TokenRequest` types** (`libs/dexie-cloud-common`)
|
|
203
|
+
- Add `AuthorizationCodeTokenRequest` type for `grant_type: "authorization_code"`
|
|
204
|
+
|
|
205
|
+
#### Types and Interfaces in dexie-cloud-addon
|
|
206
|
+
|
|
207
|
+
- [x] **Extend `LoginHints` interface** (`src/DexieCloudAPI.ts`)
|
|
208
|
+
- Add `provider?: string` - Provider name to initiate OAuth flow
|
|
209
|
+
- Add `oauthCode?: string` - Dexie auth code received from callback
|
|
210
|
+
- Keep existing `email`, `userId`, `grant_type`, `otpId`, `otp`
|
|
211
|
+
|
|
212
|
+
- [x] **Add `DXCProviderSelection` to `DXCUserInteraction`** (`src/types/DXCUserInteraction.ts`)
|
|
213
|
+
|
|
214
|
+
The current `DXCUserInteraction` only supports text input fields. For OAuth, we need clickable provider buttons. Add a new interaction type:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
/** When the system needs user to select a login method (OAuth provider or OTP) */
|
|
218
|
+
export interface DXCProviderSelection {
|
|
219
|
+
type: 'provider-selection';
|
|
220
|
+
title: string;
|
|
221
|
+
alerts: DXCAlert[];
|
|
222
|
+
providers: OAuthProviderInfo[]; // Available OAuth providers
|
|
223
|
+
otpEnabled: boolean; // Whether email/OTP option is available
|
|
224
|
+
fields: {}; // Empty - no text fields
|
|
225
|
+
submitLabel?: undefined; // No submit button - provider buttons instead
|
|
226
|
+
cancelLabel: string;
|
|
227
|
+
onSelectProvider: (providerName: string) => void;
|
|
228
|
+
onSelectOtp: () => void; // User chose email/OTP instead
|
|
229
|
+
onCancel: () => void;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Update the union type:
|
|
234
|
+
```typescript
|
|
235
|
+
export type DXCUserInteraction =
|
|
236
|
+
| DXCGenericUserInteraction
|
|
237
|
+
| DXCEmailPrompt
|
|
238
|
+
| DXCOTPPrompt
|
|
239
|
+
| DXCMessageAlert
|
|
240
|
+
| DXCLogoutConfirmation
|
|
241
|
+
| DXCProviderSelection; // NEW
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Core Authentication Flow
|
|
245
|
+
|
|
246
|
+
- [x] **Create `fetchAuthProviders()` function** (`src/authentication/fetchAuthProviders.ts`)
|
|
247
|
+
- Fetches `GET /auth-providers` from database URL
|
|
248
|
+
- Returns `AuthProvidersResponse`
|
|
249
|
+
- **Handles failures gracefully**:
|
|
250
|
+
- 404 → Return `{ providers: [], otpEnabled: true }` (old server)
|
|
251
|
+
- Network error → Return `{ providers: [], otpEnabled: true }`
|
|
252
|
+
- Log debug message for troubleshooting
|
|
253
|
+
- Cache result with TTL to avoid repeated requests
|
|
254
|
+
- Respects `socialAuth: false` option (returns empty providers without fetching)
|
|
255
|
+
|
|
256
|
+
- [x] **Update authentication flow to check providers first**
|
|
257
|
+
- Before prompting for email, call `fetchAuthProviders()`
|
|
258
|
+
- If `providers.length > 0`:
|
|
259
|
+
- Emit `DXCProviderSelection` interaction
|
|
260
|
+
- Wait for user to select provider or OTP
|
|
261
|
+
- If `providers.length === 0` or `otpEnabled` only:
|
|
262
|
+
- Emit `DXCEmailPrompt` as before (existing behavior)
|
|
263
|
+
|
|
264
|
+
- [x] **Create `oauthLogin()` function** (`src/authentication/oauthLogin.ts`)
|
|
265
|
+
- Opens popup window to `/oauth/login/:provider`
|
|
266
|
+
- Listens for `postMessage` with `type: 'dexie:oauthResult'`
|
|
267
|
+
- Validates message origin
|
|
268
|
+
- Returns auth code or throws on error/cancel
|
|
269
|
+
- Handles popup blocked scenario (fallback to redirect?)
|
|
270
|
+
|
|
271
|
+
- [x] **Create `exchangeOAuthCode()` function** (`src/authentication/exchangeOAuthCode.ts`)
|
|
272
|
+
- Sends `POST /token` with:
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"grant_type": "authorization_code",
|
|
276
|
+
"code": "<DEXIE_AUTH_CODE>",
|
|
277
|
+
"public_key": "<SPA_PUBLIC_KEY>",
|
|
278
|
+
"scopes": ["ACCESS_DB"]
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
- Returns `TokenFinalResponse`
|
|
282
|
+
|
|
283
|
+
- [x] **Update `login()` function** (`src/authentication/login.ts`)
|
|
284
|
+
- If `hints.provider` is set, use OAuth flow instead of OTP
|
|
285
|
+
- If `hints.oauthCode` is set, exchange code directly (for redirect/deep link flows)
|
|
286
|
+
- Integrate with existing `authenticate()` flow
|
|
287
|
+
|
|
288
|
+
- [x] **Create `handleOAuthCallback()` function** (`src/authentication/handleOAuthCallback.ts`)
|
|
289
|
+
- For redirect/deep link flows where app needs to handle the callback
|
|
290
|
+
- Parses `code`, `provider`, `state`, `error` from URL
|
|
291
|
+
- Completes login flow by calling `login({ oauthCode, provider })`
|
|
292
|
+
- Can be called by apps on their callback route
|
|
293
|
+
|
|
294
|
+
#### Default UI Components
|
|
295
|
+
|
|
296
|
+
- [x] **Create `ProviderSelectionDialog` component** (`src/default-ui/ProviderSelectionDialog.tsx`)
|
|
297
|
+
- Handles the new `DXCProviderSelection` interaction type
|
|
298
|
+
- Renders OAuth provider buttons
|
|
299
|
+
- Renders "Continue with email" button if `otpEnabled`
|
|
300
|
+
- Visual divider ("or") between options
|
|
301
|
+
|
|
302
|
+
- [x] **Create `AuthProviderButton` component** (`src/default-ui/AuthProviderButton.tsx`)
|
|
303
|
+
- Renders button for a single OAuth provider
|
|
304
|
+
- Displays provider icon and name
|
|
305
|
+
- Follows provider branding guidelines (Google, Apple, Microsoft have strict rules)
|
|
306
|
+
- Supports light/dark mode
|
|
307
|
+
|
|
308
|
+
- [x] **Update `LoginDialog.tsx`**
|
|
309
|
+
- Handle OAuth popup flow when provider button clicked (via `onSelectProvider`)
|
|
310
|
+
- Handle loading/error states
|
|
311
|
+
|
|
312
|
+
- [x] **Update main dialog renderer** (`src/default-ui/index.tsx`)
|
|
313
|
+
- Render `ProviderSelectionDialog` when `type === 'provider-selection'`
|
|
314
|
+
|
|
315
|
+
- [x] **Update `Styles.ts`**
|
|
316
|
+
- Add styles for OAuth provider buttons
|
|
317
|
+
- Provider-specific button colors (Google blue, GitHub black, etc.)
|
|
318
|
+
- Dark mode variants
|
|
319
|
+
|
|
320
|
+
#### Capacitor / Mobile Support
|
|
321
|
+
|
|
322
|
+
- [x] **Document deep link handling** (not library code, but patterns)
|
|
323
|
+
- Show how apps should register custom URL scheme
|
|
324
|
+
- Provide example of handling `appUrlOpen` event
|
|
325
|
+
- Call `db.cloud.login({ oauthCode, provider })` from handler
|
|
326
|
+
|
|
327
|
+
- [x] **Support `redirect_uri` configuration**
|
|
328
|
+
- Allow apps to configure their redirect URI in `db.cloud.configure()`
|
|
329
|
+
- Use for Capacitor apps with custom URL schemes
|
|
330
|
+
- Use for full-page redirect flows
|
|
331
|
+
|
|
332
|
+
#### DexieCloudOptions Extension
|
|
333
|
+
|
|
334
|
+
- [x] **Add OAuth-related options** (`src/DexieCloudOptions.ts`)
|
|
335
|
+
```typescript
|
|
336
|
+
interface DexieCloudOptions {
|
|
337
|
+
// ... existing options
|
|
338
|
+
|
|
339
|
+
/** Enable social/OAuth authentication.
|
|
340
|
+
* - true (default): Fetch providers from server, show if available
|
|
341
|
+
* - false: Disable OAuth, always use OTP flow
|
|
342
|
+
*
|
|
343
|
+
* Use `false` for backward compatibility if your custom login UI
|
|
344
|
+
* doesn't handle the `DXCProviderSelection` interaction type yet.
|
|
345
|
+
*/
|
|
346
|
+
socialAuth?: boolean;
|
|
347
|
+
|
|
348
|
+
/** Redirect URI for OAuth callback (Capacitor/redirect flows).
|
|
349
|
+
* For web popups, this is auto-detected from window.location.origin.
|
|
350
|
+
* Required for:
|
|
351
|
+
* - Capacitor apps: 'myapp://oauth-callback'
|
|
352
|
+
* - Full-page redirect flows: 'https://myapp.com/oauth-callback'
|
|
353
|
+
*/
|
|
354
|
+
oauthRedirectUri?: string;
|
|
355
|
+
|
|
356
|
+
/** Use popup window for OAuth flow.
|
|
357
|
+
* - true (default for web): Opens OAuth in popup, uses postMessage
|
|
358
|
+
* - false: Opens OAuth in same window or system browser (Capacitor)
|
|
359
|
+
*/
|
|
360
|
+
oauthPopup?: boolean;
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Error Handling
|
|
365
|
+
|
|
366
|
+
- [x] **Create `OAuthError` class** (`src/errors/OAuthError.ts`)
|
|
367
|
+
- Extends existing error handling
|
|
368
|
+
- Error codes: `popup_blocked`, `popup_closed`, `access_denied`, `invalid_state`, `email_not_verified`, `expired_code`
|
|
369
|
+
- User-friendly messages
|
|
370
|
+
|
|
371
|
+
- [x] **Handle common OAuth errors in UI**
|
|
372
|
+
- Popup blocked → show message with manual retry button
|
|
373
|
+
- User cancelled → silent failure or subtle message
|
|
374
|
+
- Provider error → show error alert
|
|
375
|
+
|
|
376
|
+
#### Testing
|
|
377
|
+
|
|
378
|
+
- [ ] **Unit tests for OAuth flow**
|
|
379
|
+
- Mock postMessage events
|
|
380
|
+
- Test popup lifecycle handling
|
|
381
|
+
- Test error scenarios
|
|
382
|
+
|
|
383
|
+
- [ ] **Integration tests**
|
|
384
|
+
- Test with mock OAuth callback page
|
|
385
|
+
- Test token exchange
|
|
386
|
+
|
|
387
|
+
**Testing tip**: The dexie-cloud-todo-app sample (`samples/dexie-cloud-todo-app`) can be used for manual testing. Configure OAuth providers in dexie-cloud-manager for your test database.
|
|
388
|
+
|
|
389
|
+
#### Documentation
|
|
390
|
+
|
|
391
|
+
- [ ] **Update README.md**
|
|
392
|
+
- Document OAuth login: `db.cloud.login({ provider: 'google' })`
|
|
393
|
+
- Show Capacitor integration pattern
|
|
394
|
+
- Explain redirect vs popup flows
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Client Integration Patterns
|
|
399
|
+
|
|
400
|
+
### Web SPA (Popup Flow - Default)
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
// User clicks "Login with Google"
|
|
404
|
+
await db.cloud.login({ provider: 'google' });
|
|
405
|
+
// Popup opens, user authenticates, popup closes, user is logged in
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Capacitor / Native App
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
// In db.cloud.configure()
|
|
412
|
+
db.cloud.configure({
|
|
413
|
+
databaseUrl: 'https://mydb.dexie.cloud',
|
|
414
|
+
oauthRedirectUri: 'myapp://oauth-callback',
|
|
415
|
+
oauthPopup: false
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// Handle deep link in app
|
|
419
|
+
App.addListener('appUrlOpen', async ({ url }) => {
|
|
420
|
+
const params = new URL(url).searchParams;
|
|
421
|
+
const code = params.get('code');
|
|
422
|
+
const provider = params.get('provider');
|
|
423
|
+
if (code && provider) {
|
|
424
|
+
await db.cloud.login({ oauthCode: code, provider });
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// Initiate login (opens system browser)
|
|
429
|
+
await db.cloud.login({ provider: 'google' });
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Full Page Redirect (No Popup)
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
db.cloud.configure({
|
|
436
|
+
databaseUrl: 'https://mydb.dexie.cloud',
|
|
437
|
+
oauthRedirectUri: 'https://myapp.com/oauth-callback',
|
|
438
|
+
oauthPopup: false
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// On /oauth-callback page:
|
|
442
|
+
const params = new URLSearchParams(window.location.search);
|
|
443
|
+
const code = params.get('code');
|
|
444
|
+
const provider = params.get('provider');
|
|
445
|
+
if (code && provider) {
|
|
446
|
+
await db.cloud.login({ oauthCode: code, provider });
|
|
447
|
+
window.history.replaceState({}, '', '/'); // Clean URL
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Architecture Diagram
|
|
454
|
+
|
|
455
|
+
```
|
|
456
|
+
┌──────────────────────────────────────────────────────────────────────────────┐
|
|
457
|
+
│ CLIENT (dexie-cloud-addon) │
|
|
458
|
+
│ │
|
|
459
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────────────┐ │
|
|
460
|
+
│ │ LoginDialog │───▶│ oauthLogin()│───▶│ Opens popup to │ │
|
|
461
|
+
│ │ (default UI)│ │ │ │ /oauth/login/:provider │ │
|
|
462
|
+
│ └─────────────┘ └─────────────┘ └─────────────────────────────────┘ │
|
|
463
|
+
│ │ │
|
|
464
|
+
│ │ Listens for postMessage │
|
|
465
|
+
│ ▼ │
|
|
466
|
+
│ ┌─────────────┐ │
|
|
467
|
+
│ │ Receives │ │
|
|
468
|
+
│ │ auth code │ │
|
|
469
|
+
│ └──────┬──────┘ │
|
|
470
|
+
│ │ │
|
|
471
|
+
│ ▼ │
|
|
472
|
+
│ ┌─────────────────┐ ┌─────────────────────────────┐ │
|
|
473
|
+
│ │exchangeOAuthCode│───▶│ POST /token │ │
|
|
474
|
+
│ │ │ │ grant_type: authorization_ │ │
|
|
475
|
+
│ │ │◀───│ code │ │
|
|
476
|
+
│ └─────────────────┘ └─────────────────────────────┘ │
|
|
477
|
+
│ │ │
|
|
478
|
+
│ ▼ │
|
|
479
|
+
│ ┌─────────────┐ │
|
|
480
|
+
│ │ User logged │ │
|
|
481
|
+
│ │ in! │ │
|
|
482
|
+
│ └─────────────┘ │
|
|
483
|
+
└──────────────────────────────────────────────────────────────────────────────┘
|
|
484
|
+
|
|
485
|
+
┌──────────────────────────────────────────────────────────────────────────────┐
|
|
486
|
+
│ DEXIE CLOUD SERVER │
|
|
487
|
+
│ │
|
|
488
|
+
│ /oauth/login/:provider │
|
|
489
|
+
│ ├── Generate state, PKCE │
|
|
490
|
+
│ ├── Store in challenges table │
|
|
491
|
+
│ └── Redirect to OAuth provider │
|
|
492
|
+
│ │
|
|
493
|
+
│ /oauth/callback/:provider ◀── OAuth provider redirects here │
|
|
494
|
+
│ ├── Verify state │
|
|
495
|
+
│ ├── Exchange code for provider tokens (server-side!) │
|
|
496
|
+
│ ├── Fetch user info, verify email │
|
|
497
|
+
│ ├── Generate Dexie auth code (single-use, 5 min TTL) │
|
|
498
|
+
│ └── Return HTML page with postMessage/redirect │
|
|
499
|
+
│ │
|
|
500
|
+
│ POST /token (grant_type: authorization_code) │
|
|
501
|
+
│ ├── Validate Dexie auth code │
|
|
502
|
+
│ ├── Extract stored user claims │
|
|
503
|
+
│ └── Return Dexie Cloud access + refresh tokens │
|
|
504
|
+
└──────────────────────────────────────────────────────────────────────────────┘
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Security Properties
|
|
510
|
+
|
|
511
|
+
- 🛡 **No provider tokens reach client** - All provider exchange happens server-side
|
|
512
|
+
- 🛡 **Single-use Dexie auth codes** - 5 minute TTL, deleted after use
|
|
513
|
+
- 🛡 **PKCE protection** - Prevents code interception (where supported)
|
|
514
|
+
- 🛡 **State parameter** - CSRF protection, stored server-side
|
|
515
|
+
- 🛡 **Origin validation** - postMessage uses captured origin, redirect_uri whitelisted
|
|
516
|
+
- 🛡 **Email verification enforced** - Server rejects unverified emails
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## Key Files to Create/Modify
|
|
521
|
+
|
|
522
|
+
**New files in dexie-cloud-common:**
|
|
523
|
+
- `src/OAuthProviderInfo.ts`
|
|
524
|
+
- `src/AuthProvidersResponse.ts`
|
|
525
|
+
- `src/OAuthResultMessage.ts`
|
|
526
|
+
- `src/AuthorizationCodeTokenRequest.ts`
|
|
527
|
+
|
|
528
|
+
**New files in dexie-cloud-addon:**
|
|
529
|
+
- `src/types/DXCUserInteraction.ts` - Add `DXCProviderSelection`
|
|
530
|
+
- `src/authentication/fetchAuthProviders.ts`
|
|
531
|
+
- `src/authentication/oauthLogin.ts`
|
|
532
|
+
- `src/authentication/exchangeOAuthCode.ts`
|
|
533
|
+
- `src/authentication/handleOAuthCallback.ts`
|
|
534
|
+
- `src/errors/OAuthError.ts`
|
|
535
|
+
- `src/default-ui/ProviderSelectionDialog.tsx`
|
|
536
|
+
- `src/default-ui/AuthProviderButton.tsx`
|
|
537
|
+
|
|
538
|
+
**Files to modify:**
|
|
539
|
+
- `src/DexieCloudAPI.ts` - Extend `LoginHints`
|
|
540
|
+
- `src/DexieCloudOptions.ts` - Add OAuth options
|
|
541
|
+
- `src/authentication/login.ts` - Integrate OAuth flow
|
|
542
|
+
- `src/authentication/interactWithUser.ts` - Add `promptForProvider()` helper
|
|
543
|
+
- `src/default-ui/index.tsx` - Render `ProviderSelectionDialog`
|
|
544
|
+
- `src/default-ui/LoginDialog.tsx` - Handle provider selection callbacks
|
|
545
|
+
- `src/default-ui/Styles.ts` - Provider button styles
|
|
@@ -17,6 +17,10 @@ export interface LoginHints {
|
|
|
17
17
|
grant_type?: 'demo' | 'otp';
|
|
18
18
|
otpId?: string;
|
|
19
19
|
otp?: string;
|
|
20
|
+
/** OAuth provider name to initiate OAuth flow (e.g., 'google', 'github') */
|
|
21
|
+
provider?: string;
|
|
22
|
+
/** Dexie Cloud authorization code received from OAuth callback */
|
|
23
|
+
oauthCode?: string;
|
|
20
24
|
}
|
|
21
25
|
export interface DexieCloudAPI {
|
|
22
26
|
version: string;
|
|
@@ -24,4 +24,24 @@ export interface DexieCloudOptions {
|
|
|
24
24
|
};
|
|
25
25
|
}) => Promise<TokenFinalResponse>;
|
|
26
26
|
awarenessProtocol?: typeof import('y-protocols/awareness');
|
|
27
|
+
/** Enable social/OAuth authentication.
|
|
28
|
+
* - true (default): Fetch providers from server, show if available
|
|
29
|
+
* - false: Disable OAuth, always use OTP flow
|
|
30
|
+
*
|
|
31
|
+
* Use `false` for backward compatibility if your custom login UI
|
|
32
|
+
* doesn't handle the `DXCProviderSelection` interaction type yet.
|
|
33
|
+
*/
|
|
34
|
+
socialAuth?: boolean;
|
|
35
|
+
/** Redirect URI for OAuth callback (Capacitor/redirect flows).
|
|
36
|
+
* For web popups, this is auto-detected from window.location.origin.
|
|
37
|
+
* Required for:
|
|
38
|
+
* - Capacitor apps: 'myapp://oauth-callback'
|
|
39
|
+
* - Full-page redirect flows: 'https://myapp.com/oauth-callback'
|
|
40
|
+
*/
|
|
41
|
+
oauthRedirectUri?: string;
|
|
42
|
+
/** Use popup window for OAuth flow.
|
|
43
|
+
* - true (default for web): Opens OAuth in popup, uses postMessage
|
|
44
|
+
* - false: Opens OAuth in same window or system browser (Capacitor)
|
|
45
|
+
*/
|
|
46
|
+
oauthPopup?: boolean;
|
|
27
47
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TokenFinalResponse } from 'dexie-cloud-common';
|
|
2
|
+
/** Options for exchanging an OAuth code */
|
|
3
|
+
export interface ExchangeOAuthCodeOptions {
|
|
4
|
+
/** The Dexie Cloud database URL */
|
|
5
|
+
databaseUrl: string;
|
|
6
|
+
/** The Dexie Cloud authorization code from OAuth callback */
|
|
7
|
+
code: string;
|
|
8
|
+
/** The client's public key in PEM format */
|
|
9
|
+
publicKey: string;
|
|
10
|
+
/** Requested scopes (defaults to ['ACCESS_DB']) */
|
|
11
|
+
scopes?: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Exchanges a Dexie Cloud authorization code for access and refresh tokens.
|
|
15
|
+
*
|
|
16
|
+
* This is called after the OAuth callback delivers the authorization code
|
|
17
|
+
* via postMessage (popup flow) or redirect.
|
|
18
|
+
*
|
|
19
|
+
* @param options - Exchange options
|
|
20
|
+
* @returns Promise resolving to TokenFinalResponse
|
|
21
|
+
* @throws OAuthError or TokenErrorResponseError on failure
|
|
22
|
+
*/
|
|
23
|
+
export declare function exchangeOAuthCode(options: ExchangeOAuthCodeOptions): Promise<TokenFinalResponse>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AuthProvidersResponse } from 'dexie-cloud-common';
|
|
2
|
+
/**
|
|
3
|
+
* Fetches available authentication providers from the Dexie Cloud server.
|
|
4
|
+
*
|
|
5
|
+
* @param databaseUrl - The Dexie Cloud database URL
|
|
6
|
+
* @param socialAuthEnabled - Whether social auth is enabled in client config (default: true)
|
|
7
|
+
* @returns Promise resolving to AuthProvidersResponse
|
|
8
|
+
*
|
|
9
|
+
* Handles failures gracefully:
|
|
10
|
+
* - 404 → Returns OTP-only (old server version)
|
|
11
|
+
* - Network error → Returns OTP-only
|
|
12
|
+
* - socialAuthEnabled: false → Returns OTP-only without fetching
|
|
13
|
+
*/
|
|
14
|
+
export declare function fetchAuthProviders(databaseUrl: string, socialAuthEnabled?: boolean): Promise<AuthProvidersResponse>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Parsed OAuth callback parameters */
|
|
2
|
+
export interface OAuthCallbackParams {
|
|
3
|
+
/** The Dexie Cloud authorization code */
|
|
4
|
+
code: string;
|
|
5
|
+
/** The OAuth provider that was used */
|
|
6
|
+
provider: string;
|
|
7
|
+
/** The state parameter for CSRF validation */
|
|
8
|
+
state: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parses OAuth callback parameters from the current URL.
|
|
12
|
+
*
|
|
13
|
+
* Use this on your OAuth callback page (for redirect/deep link flows)
|
|
14
|
+
* to extract the authorization code and complete the login.
|
|
15
|
+
*
|
|
16
|
+
* @param url - The URL to parse (defaults to window.location.href)
|
|
17
|
+
* @returns OAuthCallbackParams if valid callback, null otherwise
|
|
18
|
+
* @throws OAuthError if there's an error in the callback
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseOAuthCallback(url?: string): OAuthCallbackParams | null;
|
|
21
|
+
/**
|
|
22
|
+
* Validates the OAuth state parameter against the stored state.
|
|
23
|
+
*
|
|
24
|
+
* @param receivedState - The state from the callback URL
|
|
25
|
+
* @returns true if valid, false otherwise
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateOAuthState(receivedState: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Gets the OAuth provider from sessionStorage (for redirect flows).
|
|
30
|
+
*/
|
|
31
|
+
export declare function getStoredOAuthProvider(): string | null;
|
|
32
|
+
/**
|
|
33
|
+
* Cleans up OAuth-related query parameters from the URL.
|
|
34
|
+
* Call this after successfully handling the callback to clean up the browser URL.
|
|
35
|
+
*/
|
|
36
|
+
export declare function cleanupOAuthUrl(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Complete handler for OAuth callback pages.
|
|
39
|
+
*
|
|
40
|
+
* Parses the callback URL, validates state, and returns the parameters
|
|
41
|
+
* needed to complete the login flow.
|
|
42
|
+
*
|
|
43
|
+
* @param url - The callback URL (defaults to window.location.href)
|
|
44
|
+
* @returns OAuthCallbackParams if valid callback, null otherwise
|
|
45
|
+
* @throws OAuthError on validation failure or if callback contains an error
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* // On your OAuth callback page:
|
|
50
|
+
* const callback = handleOAuthCallback();
|
|
51
|
+
* if (callback) {
|
|
52
|
+
* await db.cloud.login({ oauthCode: callback.code, provider: callback.provider });
|
|
53
|
+
* cleanupOAuthUrl();
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function handleOAuthCallback(url?: string): OAuthCallbackParams | null;
|