@flink-app/oauth-plugin 0.12.1-alpha.38 → 0.12.1-alpha.41
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 +94 -22
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -118,7 +118,7 @@ const app = new FlinkApp<Context>({
|
|
|
118
118
|
return {
|
|
119
119
|
user,
|
|
120
120
|
token,
|
|
121
|
-
redirectUrl: "https://myapp.com/dashboard",
|
|
121
|
+
redirectUrl: "https://myapp.com/dashboard", // Plugin will add: #token=...
|
|
122
122
|
};
|
|
123
123
|
},
|
|
124
124
|
|
|
@@ -196,10 +196,12 @@ onAuthSuccess: async (
|
|
|
196
196
|
Promise<{
|
|
197
197
|
user: any;
|
|
198
198
|
token: string; // JWT token from ctx.plugins.jwtAuth.createToken()
|
|
199
|
-
redirectUrl?: string;
|
|
199
|
+
redirectUrl?: string; // Plugin appends #token=... to this URL
|
|
200
200
|
}>;
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
+
**Important:** The `redirectUrl` should NOT include the token. The plugin automatically appends `#token=...` to the URL you return.
|
|
204
|
+
|
|
203
205
|
**OAuth Profile Structure:**
|
|
204
206
|
|
|
205
207
|
```typescript
|
|
@@ -264,9 +266,53 @@ interface OAuthError {
|
|
|
264
266
|
10. Plugin calls `onAuthSuccess` callback with profile and context
|
|
265
267
|
11. App creates/links user account
|
|
266
268
|
12. **App generates JWT token via `ctx.plugins.jwtAuth.createToken()`**
|
|
267
|
-
13. **Plugin returns JWT token to client**
|
|
269
|
+
13. **Plugin returns JWT token to client via URL fragment**
|
|
268
270
|
14. Client stores JWT token and uses it for authenticated requests
|
|
269
271
|
|
|
272
|
+
### How to Extract JWT Token in Frontend
|
|
273
|
+
|
|
274
|
+
**IMPORTANT:** The plugin returns the JWT token as a **URL fragment** (`#token=...`), NOT as a query parameter (`?token=...`).
|
|
275
|
+
|
|
276
|
+
URL fragments are more secure because they are:
|
|
277
|
+
- NOT sent to the server in HTTP requests
|
|
278
|
+
- NOT logged in server access logs
|
|
279
|
+
- Only accessible to client-side JavaScript
|
|
280
|
+
|
|
281
|
+
**Correct way to extract the token:**
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
// ✅ CORRECT - Read from URL fragment (hash)
|
|
285
|
+
const hash = window.location.hash.slice(1); // Remove leading #
|
|
286
|
+
const params = new URLSearchParams(hash);
|
|
287
|
+
const token = params.get("token");
|
|
288
|
+
|
|
289
|
+
// ❌ WRONG - Reading from query parameters won't work
|
|
290
|
+
const params = new URLSearchParams(window.location.search);
|
|
291
|
+
const token = params.get("token"); // This returns null!
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**In your `onAuthSuccess` callback:**
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// ✅ CORRECT - Just return the redirectUrl, plugin adds #token=...
|
|
298
|
+
return {
|
|
299
|
+
user,
|
|
300
|
+
token,
|
|
301
|
+
redirectUrl: "https://myapp.com/dashboard",
|
|
302
|
+
};
|
|
303
|
+
// Result: https://myapp.com/dashboard#token=eyJ...
|
|
304
|
+
|
|
305
|
+
// ❌ WRONG - Don't manually add the token
|
|
306
|
+
return {
|
|
307
|
+
user,
|
|
308
|
+
token,
|
|
309
|
+
redirectUrl: `https://myapp.com/dashboard?token=${token}`,
|
|
310
|
+
};
|
|
311
|
+
// Plugin will add token again: ...?token=eyJ...#token=eyJ...
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
See [Client Integration Examples](#client-integration-examples) for complete frontend code.
|
|
315
|
+
|
|
270
316
|
### Initiate OAuth Flow
|
|
271
317
|
|
|
272
318
|
```
|
|
@@ -294,11 +340,45 @@ GET /oauth/:provider/callback?code={auth_code}&state={state}&response_type={json
|
|
|
294
340
|
|
|
295
341
|
- `code` - Authorization code from provider
|
|
296
342
|
- `state` - CSRF protection token
|
|
297
|
-
- `response_type` - Optional response format
|
|
343
|
+
- `response_type` - Optional response format: `json` for JSON response, otherwise redirect
|
|
298
344
|
|
|
299
345
|
**Response Formats:**
|
|
300
346
|
|
|
301
|
-
1. **
|
|
347
|
+
1. **URL Fragment Redirect** (default):
|
|
348
|
+
|
|
349
|
+
The plugin redirects to your `redirectUrl` with the JWT token appended as a **URL fragment** for enhanced security:
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
https://myapp.com/dashboard#token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Why fragments?** URL fragments (`#token=...`) are NOT sent to the server in HTTP requests, making them more secure than query parameters. They're only accessible to client-side JavaScript.
|
|
356
|
+
|
|
357
|
+
**Important:** Do NOT manually add the token to your `redirectUrl`. The plugin automatically appends it:
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
// ❌ WRONG - Don't do this
|
|
361
|
+
return {
|
|
362
|
+
user,
|
|
363
|
+
token,
|
|
364
|
+
redirectUrl: `${frontendUrl}/auth/callback?token=${token}`, // Plugin will add token again!
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// ✅ CORRECT - Let plugin append the token
|
|
368
|
+
return {
|
|
369
|
+
user,
|
|
370
|
+
token,
|
|
371
|
+
redirectUrl: `${frontendUrl}/auth/callback`, // Plugin adds: #token=...
|
|
372
|
+
};
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
2. **JSON Response** (when `response_type=json`):
|
|
376
|
+
|
|
377
|
+
Use `response_type=json` for API clients that need direct JSON response instead of redirect:
|
|
378
|
+
|
|
379
|
+
```
|
|
380
|
+
GET /oauth/github/callback?code=xxx&state=yyy&response_type=json
|
|
381
|
+
```
|
|
302
382
|
|
|
303
383
|
```json
|
|
304
384
|
{
|
|
@@ -311,18 +391,6 @@ GET /oauth/:provider/callback?code={auth_code}&state={state}&response_type={json
|
|
|
311
391
|
}
|
|
312
392
|
```
|
|
313
393
|
|
|
314
|
-
2. **URL Fragment** (when redirect URL supports fragments):
|
|
315
|
-
|
|
316
|
-
```
|
|
317
|
-
https://myapp.com/dashboard#token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
3. **Query Parameter** (default):
|
|
321
|
-
|
|
322
|
-
```
|
|
323
|
-
https://myapp.com/dashboard?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
324
|
-
```
|
|
325
|
-
|
|
326
394
|
## Context API
|
|
327
395
|
|
|
328
396
|
The plugin exposes methods via `ctx.plugins.oauth`:
|
|
@@ -531,15 +599,16 @@ function LoginPage() {
|
|
|
531
599
|
};
|
|
532
600
|
|
|
533
601
|
React.useEffect(() => {
|
|
534
|
-
//
|
|
535
|
-
const
|
|
536
|
-
const
|
|
602
|
+
// IMPORTANT: Token is in URL FRAGMENT (#token=...), not query parameter (?token=...)
|
|
603
|
+
const hash = window.location.hash.slice(1); // Remove the leading #
|
|
604
|
+
const params = new URLSearchParams(hash);
|
|
605
|
+
const token = params.get("token");
|
|
537
606
|
|
|
538
607
|
if (token) {
|
|
539
608
|
// Store JWT token
|
|
540
609
|
localStorage.setItem("jwt_token", token);
|
|
541
610
|
|
|
542
|
-
// Clean URL
|
|
611
|
+
// Clean URL (remove fragment)
|
|
543
612
|
window.history.replaceState({}, document.title, "/dashboard");
|
|
544
613
|
|
|
545
614
|
// Redirect to dashboard
|
|
@@ -567,7 +636,10 @@ async function loginWithGitHub() {
|
|
|
567
636
|
|
|
568
637
|
if (result.type === "success") {
|
|
569
638
|
const url = result.url;
|
|
570
|
-
|
|
639
|
+
|
|
640
|
+
// IMPORTANT: Token is in URL FRAGMENT (#token=...), not query parameter (?token=...)
|
|
641
|
+
const urlObj = new URL(url);
|
|
642
|
+
const token = new URLSearchParams(urlObj.hash.slice(1)).get("token");
|
|
571
643
|
|
|
572
644
|
if (token) {
|
|
573
645
|
await AsyncStorage.setItem("jwt_token", token);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flink-app/oauth-plugin",
|
|
3
|
-
"version": "0.12.1-alpha.
|
|
3
|
+
"version": "0.12.1-alpha.41",
|
|
4
4
|
"description": "Flink plugin for OAuth 2.0 authentication with GitHub and Google providers",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --preserve-symlinks -r ts-node/register -- node_modules/jasmine/bin/jasmine --config=./spec/support/jasmine.json",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"mongodb": "^6.15.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@flink-app/flink": "^0.12.1-alpha.
|
|
23
|
-
"@flink-app/jwt-auth-plugin": "^0.12.1-alpha.
|
|
24
|
-
"@flink-app/test-utils": "^0.12.1-alpha.
|
|
22
|
+
"@flink-app/flink": "^0.12.1-alpha.40",
|
|
23
|
+
"@flink-app/jwt-auth-plugin": "^0.12.1-alpha.41",
|
|
24
|
+
"@flink-app/test-utils": "^0.12.1-alpha.40",
|
|
25
25
|
"@types/jasmine": "^3.7.1",
|
|
26
26
|
"@types/jwt-simple": "^0.5.36",
|
|
27
27
|
"@types/node": "22.13.10",
|
|
@@ -34,5 +34,5 @@
|
|
|
34
34
|
"tsc-watch": "^4.2.9",
|
|
35
35
|
"typescript": "5.4.5"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "76b54ee31f2c10c8c8f18af91facf5322b14ebf5"
|
|
38
38
|
}
|