@maka/maka-cli 5.1.44 → 5.1.46

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 +135 -7
  4. package/bundle/typescript/src/commands/ai/mcp.sub.cmd.js.map +1 -1
  5. package/bundle/typescript/src/commands/create.js +3 -3
  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 +704 -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 +141 -0
  26. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-client.js.tsx +141 -0
  27. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-config.js.jsx +46 -0
  28. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-config.js.tsx +54 -0
  29. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-methods.js.jsx +152 -0
  30. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-methods.js.tsx +152 -0
  31. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-validator.js.jsx +143 -0
  32. package/bundle/typescript/src/templates/react/kit/auth/service/auth0-validator.js.tsx +158 -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,54 @@
1
+ /**
2
+ * Auth0 Configuration
3
+ *
4
+ * This file contains the Auth0 configuration settings.
5
+ * Set your Auth0 credentials in Meteor settings or environment variables.
6
+ */
7
+
8
+ export interface Auth0Config {
9
+ domain: string;
10
+ clientId: string;
11
+ audience?: string;
12
+ redirectUri: string;
13
+ scope: string;
14
+ }
15
+
16
+ /**
17
+ * Get Auth0 configuration from Meteor settings or environment variables
18
+ */
19
+ export const getAuth0Config = (): Auth0Config => {
20
+ if (Meteor.isClient) {
21
+ const settings = Meteor.settings.public?.auth0;
22
+
23
+ if (!settings?.domain || !settings?.clientId) {
24
+ throw new Error(
25
+ 'Auth0 configuration missing. Please add auth0 settings to your Meteor settings.json file.'
26
+ );
27
+ }
28
+
29
+ return {
30
+ domain: settings.domain,
31
+ clientId: settings.clientId,
32
+ audience: settings.audience || `https://${settings.domain}/api/v2/`,
33
+ redirectUri: settings.redirectUri || window.location.origin + '/auth/callback',
34
+ scope: settings.scope || 'openid profile email',
35
+ };
36
+ }
37
+
38
+ // Server-side configuration
39
+ const settings = Meteor.settings?.auth0;
40
+
41
+ if (!settings?.domain || !settings?.clientId) {
42
+ throw new Error(
43
+ 'Auth0 configuration missing. Please add auth0 settings to your Meteor settings.json file.'
44
+ );
45
+ }
46
+
47
+ return {
48
+ domain: settings.domain,
49
+ clientId: settings.clientId,
50
+ audience: settings.audience || `https://${settings.domain}/api/v2/`,
51
+ redirectUri: settings.redirectUri || Meteor.absoluteUrl('auth/callback'),
52
+ scope: settings.scope || 'openid profile email',
53
+ };
54
+ };
@@ -0,0 +1,152 @@
1
+ import { Meteor } from 'meteor/meteor';
2
+ import { Accounts } from 'meteor/accounts-base';
3
+ import { verifyAuth0Token, findOrCreateUserFromAuth0 } from '../auth0-validator';
4
+
5
+ /**
6
+ * Meteor Methods for Auth0 Authentication
7
+ *
8
+ * These methods handle the server-side Auth0 authentication flow,
9
+ * including token verification and user account creation/linking.
10
+ */
11
+
12
+ Meteor.methods({
13
+ /**
14
+ * Authenticate user with Auth0 ID token
15
+ *
16
+ * @param idToken - The Auth0 ID token received from the client
17
+ * @returns Object containing userId and login token
18
+ */
19
+ async 'auth0.login'(idToken) {
20
+ // Validate input
21
+ if (!idToken || typeof idToken !== 'string') {
22
+ throw new Meteor.Error('invalid-token', 'Invalid token provided');
23
+ }
24
+
25
+ try {
26
+ // Verify the Auth0 token
27
+ const tokenPayload = await verifyAuth0Token(idToken);
28
+
29
+ // Find or create user from Auth0 data
30
+ const userId = await findOrCreateUserFromAuth0(tokenPayload);
31
+
32
+ // Generate Meteor login token
33
+ const stampedLoginToken = Accounts._generateStampedLoginToken();
34
+ const loginToken = stampedLoginToken.token;
35
+
36
+ // Store login token for the user
37
+ Accounts._insertLoginToken(userId, stampedLoginToken);
38
+
39
+ // Return userId and token for client-side login
40
+ return {
41
+ userId,
42
+ token: loginToken,
43
+ tokenExpires: stampedLoginToken.when,
44
+ };
45
+ } catch (error) {
46
+ console.error('Auth0 login error:', error);
47
+
48
+ if (error instanceof Meteor.Error) {
49
+ throw error;
50
+ }
51
+
52
+ throw new Meteor.Error(
53
+ 'auth0-login-failed',
54
+ 'Failed to authenticate with Auth0',
55
+ error.message
56
+ );
57
+ }
58
+ },
59
+
60
+ /**
61
+ * Link Auth0 account to existing Meteor user
62
+ *
63
+ * @param idToken - The Auth0 ID token
64
+ */
65
+ async 'auth0.linkAccount'(idToken) {
66
+ // Must be logged in to link account
67
+ if (!this.userId) {
68
+ throw new Meteor.Error('not-authorized', 'Must be logged in to link Auth0 account');
69
+ }
70
+
71
+ if (!idToken || typeof idToken !== 'string') {
72
+ throw new Meteor.Error('invalid-token', 'Invalid token provided');
73
+ }
74
+
75
+ try {
76
+ // Verify the Auth0 token
77
+ const tokenPayload = await verifyAuth0Token(idToken);
78
+ const auth0Id = tokenPayload.sub;
79
+
80
+ // Check if Auth0 account is already linked to another user
81
+ const existingUser = Meteor.users.findOne({
82
+ 'services.auth0.id': auth0Id,
83
+ _id: { $ne: this.userId },
84
+ });
85
+
86
+ if (existingUser) {
87
+ throw new Meteor.Error(
88
+ 'auth0-already-linked',
89
+ 'This Auth0 account is already linked to another user'
90
+ );
91
+ }
92
+
93
+ // Link Auth0 account to current user
94
+ Meteor.users.update(this.userId, {
95
+ $set: {
96
+ 'services.auth0': {
97
+ id: auth0Id,
98
+ email: tokenPayload.email,
99
+ name: tokenPayload.name,
100
+ picture: tokenPayload.picture,
101
+ email_verified: tokenPayload.email_verified,
102
+ },
103
+ },
104
+ });
105
+
106
+ return { success: true };
107
+ } catch (error) {
108
+ console.error('Auth0 link account error:', error);
109
+
110
+ if (error instanceof Meteor.Error) {
111
+ throw error;
112
+ }
113
+
114
+ throw new Meteor.Error(
115
+ 'auth0-link-failed',
116
+ 'Failed to link Auth0 account',
117
+ error.message
118
+ );
119
+ }
120
+ },
121
+
122
+ /**
123
+ * Unlink Auth0 account from current user
124
+ */
125
+ 'auth0.unlinkAccount'() {
126
+ if (!this.userId) {
127
+ throw new Meteor.Error('not-authorized', 'Must be logged in to unlink Auth0 account');
128
+ }
129
+
130
+ const user = Meteor.users.findOne(this.userId);
131
+
132
+ if (!user?.services?.auth0) {
133
+ throw new Meteor.Error('no-auth0-account', 'No Auth0 account linked');
134
+ }
135
+
136
+ // Make sure user has another way to login (password or other service)
137
+ if (!user.services.password && Object.keys(user.services).length === 1) {
138
+ throw new Meteor.Error(
139
+ 'last-login-method',
140
+ 'Cannot unlink Auth0 - it is your only login method. Add a password first.'
141
+ );
142
+ }
143
+
144
+ Meteor.users.update(this.userId, {
145
+ $unset: {
146
+ 'services.auth0': '',
147
+ },
148
+ });
149
+
150
+ return { success: true };
151
+ },
152
+ });
@@ -0,0 +1,152 @@
1
+ import { Meteor } from 'meteor/meteor';
2
+ import { Accounts } from 'meteor/accounts-base';
3
+ import { verifyAuth0Token, findOrCreateUserFromAuth0 } from '../auth0-validator';
4
+
5
+ /**
6
+ * Meteor Methods for Auth0 Authentication
7
+ *
8
+ * These methods handle the server-side Auth0 authentication flow,
9
+ * including token verification and user account creation/linking.
10
+ */
11
+
12
+ Meteor.methods({
13
+ /**
14
+ * Authenticate user with Auth0 ID token
15
+ *
16
+ * @param idToken - The Auth0 ID token received from the client
17
+ * @returns Object containing userId and login token
18
+ */
19
+ async 'auth0.login'(idToken: string) {
20
+ // Validate input
21
+ if (!idToken || typeof idToken !== 'string') {
22
+ throw new Meteor.Error('invalid-token', 'Invalid token provided');
23
+ }
24
+
25
+ try {
26
+ // Verify the Auth0 token
27
+ const tokenPayload = await verifyAuth0Token(idToken);
28
+
29
+ // Find or create user from Auth0 data
30
+ const userId = await findOrCreateUserFromAuth0(tokenPayload);
31
+
32
+ // Generate Meteor login token
33
+ const stampedLoginToken = Accounts._generateStampedLoginToken();
34
+ const loginToken = stampedLoginToken.token;
35
+
36
+ // Store login token for the user
37
+ Accounts._insertLoginToken(userId, stampedLoginToken);
38
+
39
+ // Return userId and token for client-side login
40
+ return {
41
+ userId,
42
+ token: loginToken,
43
+ tokenExpires: stampedLoginToken.when,
44
+ };
45
+ } catch (error) {
46
+ console.error('Auth0 login error:', error);
47
+
48
+ if (error instanceof Meteor.Error) {
49
+ throw error;
50
+ }
51
+
52
+ throw new Meteor.Error(
53
+ 'auth0-login-failed',
54
+ 'Failed to authenticate with Auth0',
55
+ error.message
56
+ );
57
+ }
58
+ },
59
+
60
+ /**
61
+ * Link Auth0 account to existing Meteor user
62
+ *
63
+ * @param idToken - The Auth0 ID token
64
+ */
65
+ async 'auth0.linkAccount'(idToken: string) {
66
+ // Must be logged in to link account
67
+ if (!this.userId) {
68
+ throw new Meteor.Error('not-authorized', 'Must be logged in to link Auth0 account');
69
+ }
70
+
71
+ if (!idToken || typeof idToken !== 'string') {
72
+ throw new Meteor.Error('invalid-token', 'Invalid token provided');
73
+ }
74
+
75
+ try {
76
+ // Verify the Auth0 token
77
+ const tokenPayload = await verifyAuth0Token(idToken);
78
+ const auth0Id = tokenPayload.sub;
79
+
80
+ // Check if Auth0 account is already linked to another user
81
+ const existingUser = Meteor.users.findOne({
82
+ 'services.auth0.id': auth0Id,
83
+ _id: { $ne: this.userId },
84
+ });
85
+
86
+ if (existingUser) {
87
+ throw new Meteor.Error(
88
+ 'auth0-already-linked',
89
+ 'This Auth0 account is already linked to another user'
90
+ );
91
+ }
92
+
93
+ // Link Auth0 account to current user
94
+ Meteor.users.update(this.userId, {
95
+ $set: {
96
+ 'services.auth0': {
97
+ id: auth0Id,
98
+ email: tokenPayload.email,
99
+ name: tokenPayload.name,
100
+ picture: tokenPayload.picture,
101
+ email_verified: tokenPayload.email_verified,
102
+ },
103
+ },
104
+ });
105
+
106
+ return { success: true };
107
+ } catch (error) {
108
+ console.error('Auth0 link account error:', error);
109
+
110
+ if (error instanceof Meteor.Error) {
111
+ throw error;
112
+ }
113
+
114
+ throw new Meteor.Error(
115
+ 'auth0-link-failed',
116
+ 'Failed to link Auth0 account',
117
+ error.message
118
+ );
119
+ }
120
+ },
121
+
122
+ /**
123
+ * Unlink Auth0 account from current user
124
+ */
125
+ 'auth0.unlinkAccount'() {
126
+ if (!this.userId) {
127
+ throw new Meteor.Error('not-authorized', 'Must be logged in to unlink Auth0 account');
128
+ }
129
+
130
+ const user = Meteor.users.findOne(this.userId);
131
+
132
+ if (!user?.services?.auth0) {
133
+ throw new Meteor.Error('no-auth0-account', 'No Auth0 account linked');
134
+ }
135
+
136
+ // Make sure user has another way to login (password or other service)
137
+ if (!user.services.password && Object.keys(user.services).length === 1) {
138
+ throw new Meteor.Error(
139
+ 'last-login-method',
140
+ 'Cannot unlink Auth0 - it is your only login method. Add a password first.'
141
+ );
142
+ }
143
+
144
+ Meteor.users.update(this.userId, {
145
+ $unset: {
146
+ 'services.auth0': '',
147
+ },
148
+ });
149
+
150
+ return { success: true };
151
+ },
152
+ });
@@ -0,0 +1,143 @@
1
+ import { Meteor } from 'meteor/meteor';
2
+ import { Accounts } from 'meteor/accounts-base';
3
+ import jwt from 'jsonwebtoken';
4
+ import jwksClient from 'jwks-rsa';
5
+
6
+ /**
7
+ * Auth0 JWT Token Validator
8
+ *
9
+ * This module handles server-side validation of Auth0 JWT tokens
10
+ * and creates/updates Meteor user accounts based on Auth0 user data.
11
+ */
12
+
13
+ /**
14
+ * Create JWKS client for verifying Auth0 tokens
15
+ */
16
+ const getJwksClient = () => {
17
+ const auth0Domain = Meteor.settings?.auth0?.domain;
18
+
19
+ if (!auth0Domain) {
20
+ throw new Meteor.Error('auth0-config-missing', 'Auth0 domain not configured');
21
+ }
22
+
23
+ return jwksClient({
24
+ jwksUri: `https://${auth0Domain}/.well-known/jwks.json`,
25
+ cache: true,
26
+ cacheMaxAge: 86400000, // 24 hours
27
+ });
28
+ };
29
+
30
+ /**
31
+ * Get signing key for JWT verification
32
+ */
33
+ const getKey = (header, callback) => {
34
+ const client = getJwksClient();
35
+
36
+ client.getSigningKey(header.kid, (err, key) => {
37
+ if (err) {
38
+ callback(err);
39
+ return;
40
+ }
41
+ const signingKey = key?.getPublicKey();
42
+ callback(null, signingKey);
43
+ });
44
+ };
45
+
46
+ /**
47
+ * Verify Auth0 JWT token
48
+ */
49
+ export const verifyAuth0Token = (token) => {
50
+ return new Promise((resolve, reject) => {
51
+ const auth0Config = Meteor.settings?.auth0;
52
+
53
+ if (!auth0Config?.domain || !auth0Config?.clientId) {
54
+ reject(new Meteor.Error('auth0-config-missing', 'Auth0 configuration missing'));
55
+ return;
56
+ }
57
+
58
+ jwt.verify(
59
+ token,
60
+ getKey,
61
+ {
62
+ audience: auth0Config.clientId,
63
+ issuer: `https://${auth0Config.domain}/`,
64
+ algorithms: ['RS256'],
65
+ },
66
+ (err, decoded) => {
67
+ if (err) {
68
+ reject(new Meteor.Error('auth0-invalid-token', 'Invalid Auth0 token', err));
69
+ return;
70
+ }
71
+ resolve(decoded);
72
+ }
73
+ );
74
+ });
75
+ };
76
+
77
+ /**
78
+ * Find or create a Meteor user from Auth0 data
79
+ */
80
+ export const findOrCreateUserFromAuth0 = async (tokenPayload) => {
81
+ const auth0Id = tokenPayload.sub;
82
+ const email = tokenPayload.email;
83
+
84
+ // Try to find existing user by Auth0 ID
85
+ let user = Meteor.users.findOne({
86
+ 'services.auth0.id': auth0Id,
87
+ });
88
+
89
+ if (user) {
90
+ // Update user profile if needed
91
+ Meteor.users.update(user._id, {
92
+ $set: {
93
+ 'services.auth0.email': email,
94
+ 'services.auth0.name': tokenPayload.name,
95
+ 'services.auth0.picture': tokenPayload.picture,
96
+ 'services.auth0.email_verified': tokenPayload.email_verified,
97
+ },
98
+ });
99
+ return user._id;
100
+ }
101
+
102
+ // Try to find by email if email exists
103
+ if (email) {
104
+ user = Meteor.users.findOne({
105
+ 'emails.address': email,
106
+ });
107
+
108
+ if (user) {
109
+ // Link Auth0 account to existing user
110
+ Meteor.users.update(user._id, {
111
+ $set: {
112
+ 'services.auth0': {
113
+ id: auth0Id,
114
+ email: email,
115
+ name: tokenPayload.name,
116
+ picture: tokenPayload.picture,
117
+ email_verified: tokenPayload.email_verified,
118
+ },
119
+ },
120
+ });
121
+ return user._id;
122
+ }
123
+ }
124
+
125
+ // Create new user
126
+ const userId = Accounts.insertUserDoc({}, {
127
+ emails: email ? [{ address: email, verified: tokenPayload.email_verified || false }] : [],
128
+ profile: {
129
+ name: tokenPayload.name || tokenPayload.nickname || 'Auth0 User',
130
+ },
131
+ services: {
132
+ auth0: {
133
+ id: auth0Id,
134
+ email: email,
135
+ name: tokenPayload.name,
136
+ picture: tokenPayload.picture,
137
+ email_verified: tokenPayload.email_verified,
138
+ },
139
+ },
140
+ });
141
+
142
+ return userId;
143
+ };
@@ -0,0 +1,158 @@
1
+ import { Meteor } from 'meteor/meteor';
2
+ import { Accounts } from 'meteor/accounts-base';
3
+ import jwt from 'jsonwebtoken';
4
+ import jwksClient from 'jwks-rsa';
5
+
6
+ /**
7
+ * Auth0 JWT Token Validator
8
+ *
9
+ * This module handles server-side validation of Auth0 JWT tokens
10
+ * and creates/updates Meteor user accounts based on Auth0 user data.
11
+ */
12
+
13
+ interface Auth0TokenPayload {
14
+ sub: string; // Auth0 user ID
15
+ email?: string;
16
+ email_verified?: boolean;
17
+ name?: string;
18
+ nickname?: string;
19
+ picture?: string;
20
+ aud: string | string[];
21
+ iss: string;
22
+ exp: number;
23
+ iat: number;
24
+ }
25
+
26
+ /**
27
+ * Create JWKS client for verifying Auth0 tokens
28
+ */
29
+ const getJwksClient = () => {
30
+ const auth0Domain = Meteor.settings?.auth0?.domain;
31
+
32
+ if (!auth0Domain) {
33
+ throw new Meteor.Error('auth0-config-missing', 'Auth0 domain not configured');
34
+ }
35
+
36
+ return jwksClient({
37
+ jwksUri: `https://${auth0Domain}/.well-known/jwks.json`,
38
+ cache: true,
39
+ cacheMaxAge: 86400000, // 24 hours
40
+ });
41
+ };
42
+
43
+ /**
44
+ * Get signing key for JWT verification
45
+ */
46
+ const getKey = (header: any, callback: any) => {
47
+ const client = getJwksClient();
48
+
49
+ client.getSigningKey(header.kid, (err, key) => {
50
+ if (err) {
51
+ callback(err);
52
+ return;
53
+ }
54
+ const signingKey = key?.getPublicKey();
55
+ callback(null, signingKey);
56
+ });
57
+ };
58
+
59
+ /**
60
+ * Verify Auth0 JWT token
61
+ */
62
+ export const verifyAuth0Token = (token: string): Promise<Auth0TokenPayload> => {
63
+ return new Promise((resolve, reject) => {
64
+ const auth0Config = Meteor.settings?.auth0;
65
+
66
+ if (!auth0Config?.domain || !auth0Config?.clientId) {
67
+ reject(new Meteor.Error('auth0-config-missing', 'Auth0 configuration missing'));
68
+ return;
69
+ }
70
+
71
+ jwt.verify(
72
+ token,
73
+ getKey,
74
+ {
75
+ audience: auth0Config.clientId,
76
+ issuer: `https://${auth0Config.domain}/`,
77
+ algorithms: ['RS256'],
78
+ },
79
+ (err, decoded) => {
80
+ if (err) {
81
+ reject(new Meteor.Error('auth0-invalid-token', 'Invalid Auth0 token', err));
82
+ return;
83
+ }
84
+ resolve(decoded as Auth0TokenPayload);
85
+ }
86
+ );
87
+ });
88
+ };
89
+
90
+ /**
91
+ * Find or create a Meteor user from Auth0 data
92
+ */
93
+ export const findOrCreateUserFromAuth0 = async (
94
+ tokenPayload: Auth0TokenPayload
95
+ ): Promise<string> => {
96
+ const auth0Id = tokenPayload.sub;
97
+ const email = tokenPayload.email;
98
+
99
+ // Try to find existing user by Auth0 ID
100
+ let user = Meteor.users.findOne({
101
+ 'services.auth0.id': auth0Id,
102
+ });
103
+
104
+ if (user) {
105
+ // Update user profile if needed
106
+ Meteor.users.update(user._id, {
107
+ $set: {
108
+ 'services.auth0.email': email,
109
+ 'services.auth0.name': tokenPayload.name,
110
+ 'services.auth0.picture': tokenPayload.picture,
111
+ 'services.auth0.email_verified': tokenPayload.email_verified,
112
+ },
113
+ });
114
+ return user._id;
115
+ }
116
+
117
+ // Try to find by email if email exists
118
+ if (email) {
119
+ user = Meteor.users.findOne({
120
+ 'emails.address': email,
121
+ });
122
+
123
+ if (user) {
124
+ // Link Auth0 account to existing user
125
+ Meteor.users.update(user._id, {
126
+ $set: {
127
+ 'services.auth0': {
128
+ id: auth0Id,
129
+ email: email,
130
+ name: tokenPayload.name,
131
+ picture: tokenPayload.picture,
132
+ email_verified: tokenPayload.email_verified,
133
+ },
134
+ },
135
+ });
136
+ return user._id;
137
+ }
138
+ }
139
+
140
+ // Create new user
141
+ const userId = Accounts.insertUserDoc({}, {
142
+ emails: email ? [{ address: email, verified: tokenPayload.email_verified || false }] : [],
143
+ profile: {
144
+ name: tokenPayload.name || tokenPayload.nickname || 'Auth0 User',
145
+ },
146
+ services: {
147
+ auth0: {
148
+ id: auth0Id,
149
+ email: email,
150
+ name: tokenPayload.name,
151
+ picture: tokenPayload.picture,
152
+ email_verified: tokenPayload.email_verified,
153
+ },
154
+ },
155
+ });
156
+
157
+ return userId;
158
+ };