@maka/maka-cli 5.1.45 → 5.1.47

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.
Files changed (42) hide show
  1. package/.claude/settings.local.json +3 -1
  2. package/bundle/typescript/package.json +1 -1
  3. package/bundle/typescript/src/commands/ai/mcp.sub.cmd.js +118 -5
  4. package/bundle/typescript/src/commands/ai/mcp.sub.cmd.js.map +1 -1
  5. package/bundle/typescript/src/commands/create.js +2 -2
  6. package/bundle/typescript/src/commands/create.js.map +1 -1
  7. package/bundle/typescript/src/commands/run/run.command.js +0 -5
  8. package/bundle/typescript/src/commands/run/run.command.js.map +1 -1
  9. package/bundle/typescript/src/generators/kits/auth/_index.d.ts +1 -0
  10. package/bundle/typescript/src/generators/kits/auth/_index.js +1 -0
  11. package/bundle/typescript/src/generators/kits/auth/_index.js.map +1 -1
  12. package/bundle/typescript/src/generators/kits/auth/auth0-meteor.auth.gen.d.ts +1 -0
  13. package/bundle/typescript/src/generators/kits/auth/auth0-meteor.auth.gen.js +745 -0
  14. package/bundle/typescript/src/generators/kits/auth/auth0-meteor.auth.gen.js.map +1 -0
  15. package/bundle/typescript/src/generators/kits/auth/basic-meteor.auth.gen.js +2 -2
  16. package/bundle/typescript/src/generators/kits/auth/basic-meteor.auth.gen.js.map +1 -1
  17. package/bundle/typescript/src/generators/kits/mui/_index.d.ts +1 -0
  18. package/bundle/typescript/src/generators/kits/mui/_index.js +1 -0
  19. package/bundle/typescript/src/generators/kits/mui/_index.js.map +1 -1
  20. package/bundle/typescript/src/generators/kits/mui/auth0.mui.gen.d.ts +2 -0
  21. package/bundle/typescript/src/generators/kits/mui/auth0.mui.gen.js +158 -0
  22. package/bundle/typescript/src/generators/kits/mui/auth0.mui.gen.js.map +1 -0
  23. package/bundle/typescript/src/generators/publish.js +2 -6
  24. package/bundle/typescript/src/generators/publish.js.map +1 -1
  25. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-client.js.jsx +163 -0
  26. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-client.js.tsx +163 -0
  27. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-config.js.jsx +59 -0
  28. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-config.js.tsx +67 -0
  29. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-methods.js.jsx +271 -0
  30. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-methods.js.tsx +271 -0
  31. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-validator.js.jsx +179 -0
  32. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-validator.js.tsx +194 -0
  33. package/bundle/typescript/src/templates/react/kit/mui/auth0/auth-callback.js.jsx +71 -0
  34. package/bundle/typescript/src/templates/react/kit/mui/auth0/auth-callback.js.tsx +71 -0
  35. package/bundle/typescript/src/templates/react/kit/mui/auth0/auth0-account-settings.js.jsx +123 -0
  36. package/bundle/typescript/src/templates/react/kit/mui/auth0/auth0-account-settings.js.tsx +123 -0
  37. package/bundle/typescript/src/templates/react/kit/mui/auth0/auth0-login-button.js.jsx +56 -0
  38. package/bundle/typescript/src/templates/react/kit/mui/auth0/auth0-login-button.js.tsx +74 -0
  39. package/bundle/typescript/src/tools/scaffold/scaffold.class.d.ts +2 -1
  40. package/bundle/typescript/src/tools/scaffold/scaffold.class.js +12 -6
  41. package/bundle/typescript/src/tools/scaffold/scaffold.class.js.map +1 -1
  42. package/package.json +1 -1
@@ -0,0 +1,745 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { Generator } from '../../../generator.js';
4
+ import { Log } from '../../../tools/log/log.class.js';
5
+ import AuthGen from './auth.generator.js';
6
+ import MakaGen from '../../../generators/maka.gen.js';
7
+ import { ClientEngines, } from '../../../tools/fsi/fsi.interfaces.js';
8
+ Generator.create({
9
+ name: 'auth0',
10
+ aliases: ['a0'],
11
+ usage: 'maka {generate, g}:{kit, k}:{auth, a}:{auth0, a0}',
12
+ shortDesc: 'Generate Auth0 authentication integration with Meteor accounts',
13
+ validOpts: [{
14
+ name: 'force',
15
+ boolFlag: true,
16
+ description: 'Overwrite existing files'
17
+ }],
18
+ isPro: true,
19
+ resourceNameRequired: false,
20
+ mustBeInMakaProject: true,
21
+ requiredEngines: {
22
+ client: ClientEngines.REACT,
23
+ },
24
+ description: `
25
+ This kit generates an Auth0 authentication integration for your Meteor application.
26
+
27
+ It includes:
28
+ - Auth0 client SDK configuration
29
+ - Server-side JWT token validation with JWKS
30
+ - Account linking between Auth0 and Meteor
31
+ - Seamless integration with existing authentication provider
32
+ `
33
+ }, async function (args, opts) {
34
+ const { fsi, pkg, scaffold, projectConfig } = this;
35
+ try {
36
+ const shouldForce = opts.force || false;
37
+ const projectDirectory = fsi.findProjectDirectory();
38
+ const appPath = fsi.findAppDirectory();
39
+ const isSsr = projectConfig.engines.ssr === 'meteor';
40
+ const jsEngine = projectConfig.engines.js;
41
+ Log.info('Setting up Auth0 authentication...');
42
+ // Install required npm packages
43
+ Log.info('Installing Auth0 dependencies...');
44
+ await pkg.checkNpmPackage(['@auth0/auth0-spa-js', 'jsonwebtoken', 'jwks-rsa'], { shouldInstall: true });
45
+ // Ensure auth provider exists
46
+ await MakaGen.processAndRunGenerator('kit:auth:provider', [], { force: shouldForce, cwd: projectDirectory, config: projectConfig });
47
+ // Ensure auth/roles publish exists
48
+ await MakaGen.processAndRunGenerator('publish', ['auth/roles'], { force: shouldForce, globalPublish: true, cwd: projectDirectory, config: projectConfig });
49
+ const resourceTopLevelPathLib = '/imports/startup/lib';
50
+ const resourceTopLevelPathClient = isSsr ? '/imports/startup/lib' : '/imports/startup/client';
51
+ const resourceTopLevelPathServer = '/imports/startup/server';
52
+ // ===================================================================================
53
+ // 1. Generate Auth0 Configuration (Shared)
54
+ // ===================================================================================
55
+ const pathToAuth0Config = scaffold.pathFromApp({
56
+ pathParts: [
57
+ resourceTopLevelPathLib,
58
+ '',
59
+ '',
60
+ 'auth0-config'
61
+ ]
62
+ });
63
+ await scaffold.template({
64
+ srcPath: `kit/auth/service/auth0-config.js`,
65
+ destPath: `${pathToAuth0Config}.${jsEngine}`,
66
+ framework: 'react',
67
+ context: {},
68
+ config: projectConfig,
69
+ force: shouldForce,
70
+ ignore: false
71
+ });
72
+ // ===================================================================================
73
+ // 2. Generate Auth0 Client (Client-side)
74
+ // ===================================================================================
75
+ const pathToAuth0Client = scaffold.pathFromApp({
76
+ pathParts: [
77
+ resourceTopLevelPathClient,
78
+ '',
79
+ '',
80
+ 'auth0-client'
81
+ ]
82
+ });
83
+ await scaffold.template({
84
+ srcPath: `kit/auth/service/auth0-client.js`,
85
+ destPath: `${pathToAuth0Client}.${jsEngine}`,
86
+ framework: 'react',
87
+ context: {},
88
+ config: projectConfig,
89
+ force: shouldForce,
90
+ ignore: false
91
+ });
92
+ // ===================================================================================
93
+ // 3. Generate Auth0 Validator (Server-side)
94
+ // ===================================================================================
95
+ const pathToAuth0Validator = scaffold.pathFromApp({
96
+ pathParts: [
97
+ resourceTopLevelPathServer,
98
+ '',
99
+ '',
100
+ 'auth0-validator'
101
+ ]
102
+ });
103
+ await scaffold.template({
104
+ srcPath: `kit/auth/service/auth0-validator.js`,
105
+ destPath: `${pathToAuth0Validator}.${jsEngine}`,
106
+ framework: 'react',
107
+ context: {},
108
+ config: projectConfig,
109
+ force: shouldForce,
110
+ ignore: false
111
+ });
112
+ // ===================================================================================
113
+ // 4. Generate Auth0 Methods (Server-side)
114
+ // ===================================================================================
115
+ const pathToAuth0Methods = scaffold.pathFromApp({
116
+ pathParts: [
117
+ resourceTopLevelPathServer,
118
+ 'methods',
119
+ '',
120
+ 'auth0-methods'
121
+ ]
122
+ });
123
+ await scaffold.template({
124
+ srcPath: `kit/auth/service/auth0-methods.js`,
125
+ destPath: `${pathToAuth0Methods}.${jsEngine}`,
126
+ framework: 'react',
127
+ context: {},
128
+ config: projectConfig,
129
+ force: shouldForce,
130
+ ignore: false
131
+ });
132
+ // ===================================================================================
133
+ // 5. Update authentication-service with Auth0 methods
134
+ // ===================================================================================
135
+ const pathToAuthService = scaffold.pathFromApp({
136
+ pathParts: [
137
+ resourceTopLevelPathClient,
138
+ '',
139
+ '',
140
+ 'authentication-service'
141
+ ]
142
+ });
143
+ // Import Auth0 client functions
144
+ await scaffold.injectAtBeginningOfFile({
145
+ filePath: `${pathToAuthService}.${jsEngine}`,
146
+ content: `import {
147
+ loginWithAuth0Redirect,
148
+ loginWithAuth0Popup,
149
+ handleAuth0Callback,
150
+ logoutAuth0,
151
+ getAuth0IdToken,
152
+ refreshAuth0Token,
153
+ } from './auth0-client';
154
+ `
155
+ });
156
+ // Add Auth0 methods to AuthService class
157
+ const auth0Methods = `
158
+ // ============================================================================
159
+ // Auth0 Authentication Methods
160
+ // ============================================================================
161
+
162
+ /**
163
+ * Login with Auth0 using redirect flow
164
+ * User will be redirected to Auth0 login page
165
+ */
166
+ static async loginWithAuth0Redirect() {
167
+ try {
168
+ await loginWithAuth0Redirect();
169
+ } catch (error) {
170
+ console.error('Auth0 redirect login failed:', error);
171
+ throw error;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Login with Auth0 using popup flow
177
+ * Returns the authenticated Meteor user
178
+ */
179
+ static async loginWithAuth0Popup() {
180
+ try {
181
+ // Open Auth0 login popup and get ID token
182
+ const idToken = await loginWithAuth0Popup();
183
+
184
+ // Call Meteor method to validate token and create/link user
185
+ const result = await Meteor.callAsync('auth0.login', idToken);
186
+
187
+ // Login to Meteor with the generated token
188
+ return new Promise((resolve, reject) => {
189
+ Meteor.loginWithToken(result.token, (error) => {
190
+ if (error) {
191
+ reject(error);
192
+ } else {
193
+ resolve(Meteor.user());
194
+ }
195
+ });
196
+ });
197
+ } catch (error) {
198
+ console.error('Auth0 popup login failed:', error);
199
+ throw error;
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Handle Auth0 callback after redirect
205
+ * Call this method on your callback page
206
+ */
207
+ static async handleAuth0Callback() {
208
+ try {
209
+ // Handle the redirect and get ID token
210
+ const idToken = await handleAuth0Callback();
211
+
212
+ // Call Meteor method to validate token and create/link user
213
+ const result = await Meteor.callAsync('auth0.login', idToken);
214
+
215
+ // Login to Meteor with the generated token
216
+ return new Promise((resolve, reject) => {
217
+ Meteor.loginWithToken(result.token, (error) => {
218
+ if (error) {
219
+ reject(error);
220
+ } else {
221
+ resolve(Meteor.user());
222
+ }
223
+ });
224
+ });
225
+ } catch (error) {
226
+ console.error('Auth0 callback handling failed:', error);
227
+ throw error;
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Link Auth0 account to currently logged in Meteor user
233
+ */
234
+ static async linkAuth0Account() {
235
+ try {
236
+ // Get current Auth0 ID token
237
+ const idToken = await getAuth0IdToken();
238
+
239
+ // Call Meteor method to link accounts
240
+ await Meteor.callAsync('auth0.linkAccount', idToken);
241
+
242
+ return true;
243
+ } catch (error) {
244
+ console.error('Auth0 account linking failed:', error);
245
+ throw error;
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Unlink Auth0 account from current user
251
+ */
252
+ static async unlinkAuth0Account() {
253
+ try {
254
+ await Meteor.callAsync('auth0.unlinkAccount');
255
+ return true;
256
+ } catch (error) {
257
+ console.error('Auth0 account unlinking failed:', error);
258
+ throw error;
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Logout from both Auth0 and Meteor
264
+ */
265
+ static async logoutAuth0() {
266
+ try {
267
+ // Logout from Meteor first
268
+ await this.deauthenticateUser();
269
+
270
+ // Then logout from Auth0
271
+ await logoutAuth0();
272
+ } catch (error) {
273
+ console.error('Auth0 logout failed:', error);
274
+ throw error;
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Silently refresh the Auth0 token and update Meteor session
280
+ * This is called automatically when the token is about to expire
281
+ * Returns the updated expiry time
282
+ */
283
+ static async refreshAuth0Token() {
284
+ try {
285
+ // Get fresh token from Auth0 silently (using refresh token)
286
+ const idToken = await refreshAuth0Token();
287
+
288
+ // Call Meteor method to validate and update token
289
+ const result = await Meteor.callAsync('auth0.refreshToken', idToken);
290
+
291
+ return result;
292
+ } catch (error) {
293
+ console.error('Auth0 token refresh failed:', error);
294
+ throw error;
295
+ }
296
+ }
297
+ `;
298
+ await scaffold.injectIntoFile({
299
+ filePath: `${pathToAuthService}.${jsEngine}`,
300
+ content: auth0Methods,
301
+ begin: 'static async resetPasswordWithToken',
302
+ end: '}\n\nexport default AuthService',
303
+ replace: false
304
+ });
305
+ // ===================================================================================
306
+ // 6. Update authentication-provider with Auth0 context methods
307
+ // ===================================================================================
308
+ const pathToAuthProvider = scaffold.pathFromApp({
309
+ pathParts: [
310
+ resourceTopLevelPathClient,
311
+ '',
312
+ '',
313
+ 'authentication-provider'
314
+ ]
315
+ });
316
+ // Import AuthService if not already imported
317
+ await scaffold.injectAtBeginningOfFile({
318
+ filePath: `${pathToAuthProvider}.${jsEngine}`,
319
+ content: `import AuthService from './authentication-service';
320
+ `
321
+ });
322
+ // Add Auth0 methods to context value
323
+ const auth0ProviderMethods = ` loginWithAuth0Redirect: AuthService.loginWithAuth0Redirect,
324
+ loginWithAuth0Popup: AuthService.loginWithAuth0Popup,
325
+ linkAuth0Account: AuthService.linkAuth0Account,
326
+ unlinkAuth0Account: AuthService.unlinkAuth0Account,
327
+ `;
328
+ await scaffold.injectIntoFile({
329
+ filePath: `${pathToAuthProvider}.${jsEngine}`,
330
+ content: auth0ProviderMethods,
331
+ begin: 'const contextValue = useMemo\\(\\(\\) => \\(\\{',
332
+ end: '\\}\\), \\[',
333
+ replace: false
334
+ });
335
+ // Comment out the placeholder token validation in useEffect
336
+ // This prevents "Login failed: Invalid token" errors when using Meteor authentication
337
+ const authProviderFilePath = `${pathToAuthProvider}.${jsEngine}`;
338
+ const authProviderContent = fs.readFileSync(authProviderFilePath, 'utf8');
339
+ // Replace the loginUserWithToken call with a comment explaining Meteor handles this
340
+ const updatedContent = authProviderContent
341
+ .replace(/const renewedUser = await loginUserWithToken\(\);/g, '// Auth0/Meteor handles token validation automatically\n // const renewedUser = await loginUserWithToken();')
342
+ .replace(/if \(renewedUser\) \{[\s\S]*?setUserAuthorizations\(\[\]\);[\s\S]*?\}/, '// Meteor.user() is managed by Meteor\'s accounts system\n // Token validation is handled by Meteor');
343
+ fs.writeFileSync(authProviderFilePath, updatedContent, 'utf8');
344
+ // ===================================================================================
345
+ // 7. Import auth0-methods on server startup
346
+ // ===================================================================================
347
+ const serverIndexFilePath = scaffold.pathFromApp({
348
+ pathParts: [
349
+ 'imports',
350
+ 'startup',
351
+ 'server',
352
+ 'index'
353
+ ]
354
+ });
355
+ await scaffold.injectAtEndOfFile({
356
+ filePath: `${serverIndexFilePath}.${jsEngine}`,
357
+ content: `import './methods/auth0-methods';
358
+ `
359
+ });
360
+ // ===================================================================================
361
+ // 8. Create settings.json example file
362
+ // ===================================================================================
363
+ const settingsExamplePath = path.join(projectDirectory, 'settings.auth0.json');
364
+ const settingsExample = {
365
+ public: {
366
+ auth0: {
367
+ domain: 'YOUR_AUTH0_DOMAIN.auth0.com',
368
+ clientId: 'YOUR_AUTH0_CLIENT_ID',
369
+ audience: 'https://YOUR_AUTH0_DOMAIN.auth0.com/api/v2/',
370
+ redirectUri: 'http://localhost:3000/auth/callback',
371
+ scope: 'openid profile email'
372
+ }
373
+ },
374
+ auth0: {
375
+ domain: 'YOUR_AUTH0_DOMAIN.auth0.com',
376
+ clientId: 'YOUR_AUTH0_CLIENT_ID',
377
+ clientSecret: 'YOUR_AUTH0_CLIENT_SECRET',
378
+ audience: 'https://YOUR_AUTH0_DOMAIN.auth0.com/api/v2/',
379
+ redirectUri: 'http://localhost:3000/auth/callback',
380
+ scope: 'openid profile email'
381
+ }
382
+ };
383
+ if (!fsi.isFile(settingsExamplePath) || shouldForce) {
384
+ fsi.writeToFile({
385
+ filePath: settingsExamplePath,
386
+ data: JSON.stringify(settingsExample, null, 2)
387
+ });
388
+ }
389
+ // ===================================================================================
390
+ // 9. Create .env.example file
391
+ // ===================================================================================
392
+ const envExamplePath = path.join(projectDirectory, '.env.auth0.example');
393
+ const envExample = `# Auth0 Configuration
394
+ # Copy this to your settings.json or .env file and fill in your Auth0 credentials
395
+
396
+ AUTH0_DOMAIN=your-domain.auth0.com
397
+ AUTH0_CLIENT_ID=your_client_id
398
+ AUTH0_CLIENT_SECRET=your_client_secret
399
+ AUTH0_AUDIENCE=https://your-domain.auth0.com/api/v2/
400
+ AUTH0_REDIRECT_URI=http://localhost:3000/auth/callback
401
+ AUTH0_SCOPE=openid profile email
402
+ `;
403
+ if (!fsi.isFile(envExamplePath) || shouldForce) {
404
+ fsi.writeToFile({
405
+ filePath: envExamplePath,
406
+ data: envExample
407
+ });
408
+ }
409
+ // ===================================================================================
410
+ // 10. Create README documentation
411
+ // ===================================================================================
412
+ const readmePath = path.join(projectDirectory, 'README.auth0.md');
413
+ const readmeContent = `# Auth0 Authentication Integration
414
+
415
+ This document explains how Auth0 authentication has been integrated into your Meteor application.
416
+
417
+ ## Overview
418
+
419
+ This integration provides a complete Auth0 authentication solution that:
420
+
421
+ - ✅ Supports both redirect and popup login flows
422
+ - ✅ Validates JWT tokens server-side using JWKS
423
+ - ✅ Automatically creates or links Meteor user accounts
424
+ - ✅ Allows account linking for existing users
425
+ - ✅ Provides seamless integration with your existing AuthContext
426
+
427
+ ## Architecture
428
+
429
+ ### Client-Side Components
430
+
431
+ **\`${resourceTopLevelPathLib}/auth0-config.${jsEngine}\`**
432
+ - Centralized Auth0 configuration
433
+ - Reads settings from \`Meteor.settings.public.auth0\`
434
+ - Provides configuration for both client and server
435
+
436
+ **\`${resourceTopLevelPathClient}/auth0-client.${jsEngine}\`**
437
+ - Auth0 SDK wrapper functions
438
+ - Handles login redirects and popups
439
+ - Manages Auth0 client instance
440
+ - Retrieves ID tokens
441
+
442
+ **\`${resourceTopLevelPathClient}/authentication-service.${jsEngine}\`**
443
+ - Extended with Auth0 authentication methods
444
+ - Bridges Auth0 with Meteor accounts
445
+ - Provides static methods for all Auth0 operations
446
+
447
+ **\`${resourceTopLevelPathClient}/authentication-provider.${jsEngine}\`**
448
+ - Context updated with Auth0 methods
449
+ - Makes Auth0 functions available throughout your app
450
+
451
+ ### Server-Side Components
452
+
453
+ **\`${resourceTopLevelPathServer}/auth0-validator.${jsEngine}\`**
454
+ - JWT token validation using JWKS
455
+ - Verifies token signature and claims
456
+ - Creates/updates user accounts from Auth0 data
457
+
458
+ **\`${resourceTopLevelPathServer}/methods/auth0-methods.${jsEngine}\`**
459
+ - Meteor methods for Auth0 operations
460
+ - \`auth0.login\` - Authenticates with ID token
461
+ - \`auth0.linkAccount\` - Links Auth0 to existing user
462
+ - \`auth0.unlinkAccount\` - Removes Auth0 link
463
+
464
+ ## Setup Instructions
465
+
466
+ ### 1. Configure Auth0 Application
467
+
468
+ 1. Go to [Auth0 Dashboard](https://manage.auth0.com/)
469
+ 2. Create a new application (Single Page Application)
470
+ 3. Configure the following settings:
471
+ - **Allowed Callback URLs**: \`http://localhost:3000/auth/callback\`
472
+ - **Allowed Logout URLs**: \`http://localhost:3000\`
473
+ - **Allowed Web Origins**: \`http://localhost:3000\`
474
+ - **Allowed Origins (CORS)**: \`http://localhost:3000\`
475
+
476
+ ### 2. Update Configuration
477
+
478
+ Edit \`settings.auth0.json\` with your Auth0 credentials:
479
+
480
+ \`\`\`json
481
+ {
482
+ "public": {
483
+ "auth0": {
484
+ "domain": "your-domain.auth0.com",
485
+ "clientId": "your_client_id",
486
+ "audience": "https://your-domain.auth0.com/api/v2/",
487
+ "redirectUri": "http://localhost:3000/auth/callback",
488
+ "scope": "openid profile email"
489
+ }
490
+ },
491
+ "auth0": {
492
+ "domain": "your-domain.auth0.com",
493
+ "clientId": "your_client_id",
494
+ "clientSecret": "your_client_secret",
495
+ "audience": "https://your-domain.auth0.com/api/v2/",
496
+ "redirectUri": "http://localhost:3000/auth/callback",
497
+ "scope": "openid profile email"
498
+ }
499
+ }
500
+ \`\`\`
501
+
502
+ ### 3. Start Your Application
503
+
504
+ \`\`\`bash
505
+ cd app
506
+ meteor --settings ../settings.auth0.json
507
+ \`\`\`
508
+
509
+ ## Usage
510
+
511
+ ### Using Auth0 in Components
512
+
513
+ The Auth0 methods are available through the AuthContext:
514
+
515
+ \`\`\`${jsEngine === 'tsx' ? 'typescript' : 'javascript'}
516
+ import React, { useContext } from 'react';
517
+ import { AuthContext } from '${resourceTopLevelPathClient}/authentication-provider';
518
+
519
+ function LoginButton() {
520
+ const auth = useContext(AuthContext);
521
+
522
+ const handleLogin = async () => {
523
+ try {
524
+ // Option 1: Redirect flow (recommended)
525
+ await auth.loginWithAuth0Redirect?.();
526
+
527
+ // Option 2: Popup flow
528
+ // const user = await auth.loginWithAuth0Popup?.();
529
+ // console.log('Logged in user:', user);
530
+ } catch (error) {
531
+ console.error('Login failed:', error);
532
+ }
533
+ };
534
+
535
+ return <button onClick={handleLogin}>Login with Auth0</button>;
536
+ }
537
+ \`\`\`
538
+
539
+ ### Using AuthService Directly
540
+
541
+ You can also use the AuthService static methods:
542
+
543
+ \`\`\`${jsEngine === 'tsx' ? 'typescript' : 'javascript'}
544
+ import AuthService from '${resourceTopLevelPathClient}/authentication-service';
545
+
546
+ // Redirect login
547
+ await AuthService.loginWithAuth0Redirect();
548
+
549
+ // Popup login
550
+ const user = await AuthService.loginWithAuth0Popup();
551
+
552
+ // Handle callback (use in callback page)
553
+ const user = await AuthService.handleAuth0Callback();
554
+
555
+ // Link Auth0 to logged-in user
556
+ await AuthService.linkAuth0Account();
557
+
558
+ // Unlink Auth0 account
559
+ await AuthService.unlinkAuth0Account();
560
+
561
+ // Logout from both Auth0 and Meteor
562
+ await AuthService.logoutAuth0();
563
+ \`\`\`
564
+
565
+ ## Authentication Flow
566
+
567
+ ### Redirect Flow
568
+
569
+ 1. User clicks login button
570
+ 2. \`loginWithAuth0Redirect()\` redirects to Auth0 login page
571
+ 3. User authenticates with Auth0
572
+ 4. Auth0 redirects back to \`/auth/callback\`
573
+ 5. Callback page calls \`handleAuth0Callback()\`
574
+ 6. Server validates JWT and creates/links Meteor user
575
+ 7. User is logged into Meteor and redirected to home page
576
+
577
+ ### Popup Flow
578
+
579
+ 1. User clicks login button
580
+ 2. \`loginWithAuth0Popup()\` opens Auth0 login in popup
581
+ 3. User authenticates with Auth0
582
+ 4. Popup closes and ID token is returned
583
+ 5. Server validates JWT and creates/links Meteor user
584
+ 6. User is logged into Meteor
585
+ 7. Component receives user object
586
+
587
+ ## Account Linking
588
+
589
+ Users can link their Auth0 account to an existing Meteor account:
590
+
591
+ \`\`\`${jsEngine === 'tsx' ? 'typescript' : 'javascript'}
592
+ // User must be logged in first
593
+ const auth = useContext(AuthContext);
594
+ await auth.linkAuth0Account?.();
595
+ \`\`\`
596
+
597
+ This allows users to:
598
+ - Login with either Meteor credentials or Auth0
599
+ - Maintain a single user account with multiple login methods
600
+ - Unlink Auth0 if they no longer want to use it
601
+
602
+ ## User Data Structure
603
+
604
+ When a user logs in with Auth0, their Meteor user document includes:
605
+
606
+ \`\`\`javascript
607
+ {
608
+ _id: "userId",
609
+ emails: [{ address: "user@example.com", verified: true }],
610
+ profile: { name: "John Doe" },
611
+ services: {
612
+ auth0: {
613
+ id: "auth0|123456789",
614
+ email: "user@example.com",
615
+ name: "John Doe",
616
+ picture: "https://...",
617
+ email_verified: true
618
+ }
619
+ }
620
+ }
621
+ \`\`\`
622
+
623
+ ## Security Features
624
+
625
+ - **JWT Validation**: Tokens are verified using Auth0's JWKS endpoint
626
+ - **Token Expiration**: Tokens are checked for expiration
627
+ - **Issuer Verification**: Ensures tokens come from your Auth0 domain
628
+ - **Audience Verification**: Validates tokens are for your application
629
+ - **Account Linking Protection**: Prevents duplicate account linking
630
+
631
+ ## Troubleshooting
632
+
633
+ ### "Login failed: Invalid token" Error After Successful Login
634
+
635
+ If you see this error message even though you're logged in, it's because the placeholder token validation code is still running. The Auth0 kit automatically comments out this code, but if you see this error:
636
+
637
+ 1. Check your \`authentication-provider.${jsEngine}\` file
638
+ 2. Look for the \`loginUserWithToken\` call in the \`useEffect\` hook
639
+ 3. Ensure it's commented out (the generator does this automatically)
640
+ 4. Meteor's authentication system handles token validation automatically
641
+
642
+ ### "Invalid token" Error During Login
643
+
644
+ - Check that your Auth0 domain and clientId are correct
645
+ - Verify the token hasn't expired
646
+ - Ensure your Auth0 application settings are configured correctly
647
+ - Make sure the domain in settings.json doesn't include \`https://\` (the kit handles this automatically)
648
+
649
+ ### "Auth0 configuration missing" Error
650
+
651
+ - Make sure you're starting Meteor with \`--settings ../settings.auth0.json\`
652
+ - Verify the settings file contains all required Auth0 configuration
653
+
654
+ ### Callback URL Mismatch
655
+
656
+ - Ensure the callback URL in Auth0 dashboard matches your \`redirectUri\`
657
+ - For production, update the callback URL to your production domain
658
+
659
+ ### CORS Errors
660
+
661
+ - Add your domain to "Allowed Web Origins" in Auth0 dashboard
662
+ - Ensure "Allowed Origins (CORS)" includes your domain
663
+
664
+ ## API Reference
665
+
666
+ ### AuthService Methods
667
+
668
+ #### \`loginWithAuth0Redirect()\`
669
+ Redirects user to Auth0 login page. User will leave your application.
670
+
671
+ **Returns**: Promise<void>
672
+
673
+ #### \`loginWithAuth0Popup()\`
674
+ Opens Auth0 login in a popup window. User stays on your application.
675
+
676
+ **Returns**: Promise<User>
677
+
678
+ #### \`handleAuth0Callback()\`
679
+ Handles the OAuth callback after redirect. Call this on your callback page.
680
+
681
+ **Returns**: Promise<User>
682
+
683
+ #### \`linkAuth0Account()\`
684
+ Links Auth0 account to currently logged-in Meteor user.
685
+
686
+ **Returns**: Promise<boolean>
687
+
688
+ **Throws**: Error if user not logged in or account already linked
689
+
690
+ #### \`unlinkAuth0Account()\`
691
+ Removes Auth0 link from current user.
692
+
693
+ **Returns**: Promise<boolean>
694
+
695
+ **Throws**: Error if Auth0 is the only login method
696
+
697
+ #### \`logoutAuth0()\`
698
+ Logs out from both Meteor and Auth0.
699
+
700
+ **Returns**: Promise<void>
701
+
702
+ ## Next Steps
703
+
704
+ 1. **Generate UI Components**: Run \`maka g:k:m:auth0\` to generate MUI login components
705
+ 2. **Customize User Profile**: Add additional user fields from Auth0 token
706
+ 3. **Add Roles**: Integrate with \`alanning:roles\` for authorization
707
+ 4. **Production Setup**: Update callback URLs for production domain
708
+ 5. **Social Connections**: Enable social login providers in Auth0 dashboard
709
+
710
+ ## Additional Resources
711
+
712
+ - [Auth0 Documentation](https://auth0.com/docs)
713
+ - [Auth0 SPA SDK](https://auth0.com/docs/libraries/auth0-spa-js)
714
+ - [Meteor Accounts](https://docs.meteor.com/api/accounts.html)
715
+ - [JWT.io](https://jwt.io/) - Debug JWT tokens
716
+
717
+ ## Support
718
+
719
+ For issues specific to this integration, please check:
720
+ - Auth0 dashboard for application configuration
721
+ - Browser console for client-side errors
722
+ - Meteor server logs for server-side errors
723
+ - Network tab to inspect Auth0 API calls
724
+ `;
725
+ if (!fsi.isFile(readmePath) || shouldForce) {
726
+ fsi.writeToFile({
727
+ filePath: readmePath,
728
+ data: readmeContent
729
+ });
730
+ Log.success('✓ Created README.auth0.md documentation');
731
+ }
732
+ Log.success('\n✓ Auth0 authentication integration generated successfully!');
733
+ Log.info('\nNext steps:');
734
+ Log.info('1. Configure your Auth0 application at https://manage.auth0.com/');
735
+ Log.info('2. Update settings.auth0.json with your Auth0 credentials');
736
+ Log.info('3. Start your app with: meteor --settings ../settings.auth0.json');
737
+ Log.info('4. Use AuthService.loginWithAuth0Redirect() or AuthService.loginWithAuth0Popup() in your components');
738
+ Log.info('\n📖 For detailed documentation, see README.auth0.md');
739
+ }
740
+ catch (e) {
741
+ Log.error(e);
742
+ process.exit(1);
743
+ }
744
+ }, async function () { }, AuthGen);
745
+ //# sourceMappingURL=auth0-meteor.auth.gen.js.map