forked from auth0/rules
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rules.json
620 lines (620 loc) · 82.8 KB
/
rules.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
[
{
"name": "access control",
"templates": [
{
"id": "access-on-weekdays-only-for-an-app",
"title": "Allow Access during weekdays for a specific App",
"overview": "Prevent access to app during weekends.",
"categories": [
"access control"
],
"description": "<p>This rule is used to prevent access during weekends for a specific app.</p>",
"code": "function (user, context, callback) {\n\n if (context.clientName === 'TheAppToCheckAccessTo') {\n const d = Date.getDay();\n\n if (d === 0 || d === 6) {\n return callback(new UnauthorizedError('This app is available during the week'));\n }\n }\n\n callback(null, user, context);\n}"
},
{
"id": "active-directory-groups",
"title": "Active Directory group membership",
"overview": "Check Active Directory membership, else return Access Denied.",
"categories": [
"access control"
],
"description": "<p>This rule checks if a user belongs to an AD group and if not, it will return Access Denied.</p>\n<blockquote>\n <p>Note: you can mix this with <code>context.clientID</code> or <code>clientName</code> to do it only for specific application</p>\n</blockquote>",
"code": "function (user, context, callback) {\n var groupAllowed = 'group1';\n if (user.groups) {\n var userHasAccess = user.groups.some(\n function (group) {\n return groupAllowed === group;\n });\n\n if (!userHasAccess) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n }\n\n callback(null, user, context);\n}"
},
{
"id": "check-domains-against-connection-aliases",
"title": "Check if user email domain matches configured domain",
"overview": "Check user email domain matches domains configured in connection.",
"categories": [
"access control"
],
"description": "<p>This rule checks if the user's login email matches any domains configured in an enterprise connection. If there are no matches, the login is denied. But, if there are no domains configured it will allow access.</p>\n<p>Use this rule to only allow users from specific email domains to login.</p>\n<p>For example, ExampleCo has setup exampleco.com as a managed domain. They add exampleco.com to the email domains list in their SAML connection. Now, only users with an email ending with @exampleco.com (and not @examplecocorp.com) can login via SAML.</p>",
"code": "function (user, context, callback) {\n const connectionOptions = context.connectionOptions;\n const domainAliases = connectionOptions.domain_aliases || [];\n const tenantDomain = connectionOptions.tenant_domain;\n\n // No domains -> access allowed\n if (!tenantDomain && !domainAliases.length) {\n return callback(null, user, context);\n }\n\n // Domain aliases exist but no tenant domain exists\n if (domainAliases.length && !tenantDomain) return callback('Access denied');\n\n const allowedDomains = new Set([tenantDomain]);\n domainAliases.forEach(function (alias) {\n if (alias) allowedDomains.add(alias.toLowerCase());\n });\n\n // Access allowed if domain is found\n const emailSplit = user.email.split('@');\n const userEmailDomain = emailSplit[emailSplit.length - 1].toLowerCase();\n if (allowedDomains.has(userEmailDomain)) return callback(null, user, context);\n\n return callback('Access denied');\n}"
},
{
"id": "check-last-password-reset",
"title": "Check last password reset",
"overview": "Check the last time that a user changed his or her account password.",
"categories": [
"access control"
],
"description": "<p>This rule will check the last time that a user changed his or her account password.</p>",
"code": "function (user, context, callback) {\n function daydiff (first, second) {\n return (second-first)/(1000*60*60*24);\n }\n\n const last_password_change = user.last_password_reset || user.created_at;\n\n if (daydiff(new Date(last_password_change), new Date()) > 30) {\n return callback(new UnauthorizedError('please change your password'));\n }\n callback(null, user, context);\n}"
},
{
"id": "disable-resource-owner",
"title": "Disable the Resource Owner endpoint",
"overview": "Disable the Resource Owner endpoint to prevent users from bypassing MFA policies.",
"categories": [
"access control"
],
"description": "<p>This rule is used to disable the Resource Owner endpoint (to prevent users from bypassing MFA policies).</p>",
"code": "function (user, context, callback) {\n if (context.protocol === 'oauth2-resource-owner') {\n return callback(\n new UnauthorizedError('The resource owner endpoint cannot be used.'));\n }\n callback(null, user, context);\n}"
},
{
"id": "disable-social-signup",
"title": "Disable social signups",
"overview": "Disable signups from social connections.",
"categories": [
"access control"
],
"description": "<p>This rule is used to prevent signups using social connections.</p>",
"code": "function (user, context, callback) {\n\n const CLIENTS_ENABLED = ['REPLACE_WITH_YOUR_CLIENT_ID'];\n // run only for the specified clients\n if (CLIENTS_ENABLED.indexOf(context.clientID) === -1) {\n return callback(null, user, context);\n }\n\n // initialize app_metadata\n user.app_metadata = user.app_metadata || {};\n\n const is_social = context.connectionStrategy === context.connection;\n // if it is the first login (hence the `signup`) and it is a social login\n if (context.stats.loginsCount === 1 && is_social) {\n\n // turn on the flag\n user.app_metadata.is_signup = true;\n\n // store the app_metadata\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata)\n .then(function(){\n // throw error\n return callback(new Error('Signup disabled'));\n })\n .catch(function(err){\n callback(err);\n });\n\n return;\n }\n\n // if flag is enabled, throw error\n if (user.app_metadata.is_signup) {\n return callback(new Error('Signup disabled'));\n }\n\n // else it is a non social login or it is not a signup\n callback(null, user, context);\n}"
},
{
"id": "dropbox-whitelist",
"title": "Whitelist on the cloud",
"overview": "Determine access to users based on a whitelist of emails stored in Dropbox.",
"categories": [
"access control"
],
"description": "<p>This rule denies/grant access to users based on a list of emails stored in Dropbox.</p>",
"code": "function (user, context, callback) {\n\n // Access should only be granted to verified users.\n if (!user.email || !user.email_verified) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n request.get({\n url: 'https://dl.dropboxusercontent.com/u/12345678/email_list.txt'\n }, (err, response, body) => {\n const whitelist = body.split('\\n');\n\n const userHasAccess = whitelist.some(function (email) {\n return email === user.email;\n });\n\n if (!userHasAccess) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n callback(null, user, context);\n });\n}"
},
{
"id": "email-verified",
"title": "Force email verification",
"overview": "Only allow access to users with verified emails.",
"categories": [
"access control"
],
"description": "<p>This rule will only allow access users that have verified their emails.</p>\n<blockquote>\n <p>Note: It might be a better UX to make this verification from your application.</p>\n</blockquote>\n<p>If you are using <a href=\"https://auth0.com/docs/lock\">Lock</a>, the default behavior is to log in a user immediately after they have signed up.\nTo prevent this from immediately displaying an error to the user, you can pass the following option to <code>lock.show()</code> or similar: <code>loginAfterSignup: false</code>.</p>\n<p>If you are using <a href=\"https://auth0.com/docs/libraries/auth0js\">auth0.js</a>, the equivalent option is <code>auto_login: false</code>.</p>",
"code": "function (user, context, callback) {\n if (!user.email_verified) {\n return callback(new UnauthorizedError('Please verify your email before logging in.'));\n } else {\n return callback(null, user, context);\n }\n}"
},
{
"id": "ip-address-whitelist",
"title": "IP Address whitelist",
"overview": "Only allow access to an app from a specific set of IP addresses.",
"categories": [
"access control"
],
"description": "<p>This rule will only allow access to an app from a specific set of IP addresses</p>",
"code": "function (user, context, callback) {\n const whitelist = ['1.2.3.4', '2.3.4.5']; // authorized IPs\n const userHasAccess = whitelist.some(function (ip) {\n return context.request.ip === ip;\n });\n\n if (!userHasAccess) {\n return callback(new Error('Access denied from this IP address.'));\n }\n\n return callback(null, user, context);\n}"
},
{
"id": "link-users-by-email-with-metadata",
"title": "Link Accounts with Same Email Address while Merging Metadata",
"overview": "Link any accounts that have the same email address while merging metadata.",
"categories": [
"access control"
],
"description": "<p>This rule will link any accounts that have the same email address while merging metadata.</p>",
"code": "function (user, context, callback) {\n const request = require('request');\n\n // Check if email is verified, we shouldn't automatically\n // merge accounts if this is not the case.\n if (!user.email || !user.email_verified) {\n return callback(null, user, context);\n }\n\n const userApiUrl = auth0.baseUrl + '/users';\n const userSearchApiUrl = auth0.baseUrl + '/users-by-email';\n\n request({\n url: userSearchApiUrl,\n headers: {\n Authorization: 'Bearer ' + auth0.accessToken\n },\n qs: {\n email: user.email\n }\n },\n function (err, response, body) {\n if (err) return callback(err);\n if (response.statusCode !== 200) return callback(new Error(body));\n\n var data = JSON.parse(body);\n // Ignore non-verified users and current user, if present\n data = data.filter(function (u) {\n return u.email_verified && (u.user_id !== user.user_id);\n });\n\n if (data.length > 1) {\n return callback(new Error('[!] Rule: Multiple user profiles already exist - cannot select base profile to link with'));\n }\n if (data.length === 0) {\n console.log('[-] Skipping link rule');\n return callback(null, user, context);\n }\n\n const originalUser = data[0];\n const provider = user.identities[0].provider;\n const providerUserId = user.identities[0].user_id;\n\n user.app_metadata = user.app_metadata || {};\n user.user_metadata = user.user_metadata || {};\n auth0.users.updateAppMetadata(originalUser.user_id, user.app_metadata)\n .then(auth0.users.updateUserMetadata(originalUser.user_id, user.user_metadata))\n .then(function() {\n request.post({\n url: userApiUrl + '/' + originalUser.user_id + '/identities',\n headers: {\n Authorization: 'Bearer ' + auth0.accessToken\n },\n json: { provider: provider, user_id: String(providerUserId) }\n }, function (err, response, body) {\n if (response && response.statusCode >= 400) {\n return callback(new Error('Error linking account: ' + response.statusMessage));\n }\n context.primaryUser = originalUser.user_id;\n callback(null, user, context);\n });\n })\n .catch(function (err) {\n callback(err);\n });\n });\n}"
},
{
"id": "link-users-by-email",
"title": "Link Accounts with Same Email Address",
"overview": "Link any accounts that have the same email address.",
"categories": [
"access control"
],
"description": "<p>This rule will link any accounts that have the same email address.</p>\n<blockquote>\n <p>Note: When linking accounts, only the metadata of the target user is saved. If you want to merge the metadata of the two accounts you must do that manually. See the document on <a href=\"https://auth0.com/docs/link-accounts\">Linking Accounts</a> for more details.</p>\n</blockquote>",
"code": "function (user, context, callback) {\n const request = require('request');\n // Check if email is verified, we shouldn't automatically\n // merge accounts if this is not the case.\n if (!user.email || !user.email_verified) {\n return callback(null, user, context);\n }\n const userApiUrl = auth0.baseUrl + '/users';\n const userSearchApiUrl = auth0.baseUrl + '/users-by-email';\n\n request({\n url: userSearchApiUrl,\n headers: {\n Authorization: 'Bearer ' + auth0.accessToken\n },\n qs: {\n email: user.email\n }\n },\n function(err, response, body) {\n if (err) return callback(err);\n if (response.statusCode !== 200) return callback(new Error(body));\n\n var data = JSON.parse(body);\n // Ignore non-verified users and current user, if present\n data = data.filter(function(u) {\n return u.email_verified && (u.user_id !== user.user_id);\n });\n\n if (data.length > 1) {\n return callback(new Error('[!] Rule: Multiple user profiles already exist - cannot select base profile to link with'));\n }\n if (data.length === 0) {\n console.log('[-] Skipping link rule');\n return callback(null, user, context);\n }\n\n const originalUser = data[0];\n const provider = user.identities[0].provider;\n const providerUserId = user.identities[0].user_id;\n\n request.post({\n url: userApiUrl + '/' + originalUser.user_id + '/identities',\n headers: {\n Authorization: 'Bearer ' + auth0.accessToken\n },\n json: {\n provider: provider,\n user_id: String(providerUserId)\n }\n }, function(err, response, body) {\n if (response.statusCode >= 400) {\n return callback(new Error('Error linking account: ' + response.statusMessage));\n }\n context.primaryUser = originalUser.user_id;\n callback(null, user, context);\n });\n });\n}"
},
{
"id": "roles-creation",
"title": "Set roles to a user",
"overview": "Add a Roles field to the user based on some pattern.",
"categories": [
"access control"
],
"description": "<p>This rule adds a Roles field to the user based on some pattern.</p>",
"code": "function (user, context, callback) {\n\n // Roles should only be set to verified users.\n if (!user.email || !user.email_verified) {\n return callback(null, user, context);\n }\n\n user.app_metadata = user.app_metadata || {};\n // You can add a Role based on what you want\n // In this case I check domain\n const addRolesToUser = function(user) {\n const endsWith = '@example.com';\n\n if (user.email && (user.email.substring(user.email.length - endsWith.length, user.email.length) === endsWith)) {\n return ['admin']\n }\n return ['user'];\n };\n\n const roles = addRolesToUser(user);\n\n user.app_metadata.roles = roles;\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata)\n .then(function() {\n context.idToken['https://example.com/roles'] = user.app_metadata.roles;\n callback(null, user, context);\n })\n .catch(function (err) {\n callback(err);\n });\n}"
},
{
"id": "simple-domain-whitelist",
"title": "Email domain whitelist",
"overview": "Only allow access to users with specific whitelist email domains.",
"categories": [
"access control"
],
"description": "<p>This rule will only allow access to users with specific email domains.</p>",
"code": "function (user, context, callback) {\n\n // Access should only be granted to verified users.\n if (!user.email || !user.email_verified) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n const whitelist = ['example.com', 'example.org']; //authorized domains\n const userHasAccess = whitelist.some(\n function (domain) {\n const emailSplit = user.email.split('@');\n return emailSplit[emailSplit.length - 1].toLowerCase() === domain;\n });\n\n if (!userHasAccess) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n return callback(null, user, context);\n}"
},
{
"id": "simple-user-whitelist-for-app",
"title": "Whitelist for a Specific App",
"overview": "Only allow access to users with whitelist email addresses on a specific app",
"categories": [
"access control"
],
"description": "<p>This rule will only allow access to users with specific email addresses on a specific app.</p>",
"code": "function (user, context, callback) {\n\n // Access should only be granted to verified users.\n if (!user.email || !user.email_verified) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n // only enforce for NameOfTheAppWithWhiteList\n // bypass this rule for all other apps\n if(context.clientName !== 'NameOfTheAppWithWhiteList'){\n return callback(null, user, context);\n }\n\n const whitelist = [ '[email protected]', '[email protected]' ]; // authorized users\n const userHasAccess = whitelist.some(function (email) {\n return email === user.email;\n });\n\n if (!userHasAccess) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n callback(null, user, context);\n}"
},
{
"id": "simple-user-whitelist",
"title": "Whitelist",
"overview": "Only allow access to users with specific whitelist email addresses.",
"categories": [
"access control"
],
"description": "<p>This rule will only allow access to users with specific email addresses.</p>",
"code": "function (user, context, callback) {\n\n // Access should only be granted to verified users.\n if (!user.email || !user.email_verified) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n const whitelist = [ '[email protected]', '[email protected]' ]; //authorized users\n const userHasAccess = whitelist.some(\n function (email) {\n return email === user.email;\n });\n\n if (!userHasAccess) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n callback(null, user, context);\n}"
},
{
"id": "simple-whitelist-on-a-connection",
"title": "Whitelist on Specific Connection",
"overview": "Only allow access to users coming from a whitelist on specific connection.",
"categories": [
"access control"
],
"description": "<p>This rule will only allow access to certain users coming from a specific connection (e.g. fitbit).</p>",
"code": "function (user, context, callback) {\n\n // Access should only be granted to verified users.\n if (!user.email || !user.email_verified) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n\n // We check users only authenticated with 'fitbit'\n if(context.connection === 'fitbit') {\n const whitelist = [ '[email protected]', '[email protected]' ]; //authorized user emails\n const userHasAccess = whitelist.some(function (email) {\n return (email === user.email);\n });\n\n if (!userHasAccess) {\n return callback(new UnauthorizedError('Access denied.'));\n }\n }\n\n callback(null, user, context);\n}"
}
]
},
{
"name": "enrich profile",
"templates": [
{
"id": "add-attributes",
"title": "Add attributes to a user for specific connection",
"overview": "Add attributes to a user for specific connection.",
"categories": [
"enrich profile"
],
"description": "<p>This rule will add an attribute to the user only for the login transaction (i.e. they won't be persisted to the user).</p>\n<p>This is useful for cases where you want to enrich the user information for a specific application.</p>",
"code": "function (user, context, callback) {\n if (context.connection === 'company.com') {\n context.idToken['https://example.com/vip'] = true;\n }\n\n callback(null, user, context);\n}"
},
{
"id": "add-country",
"title": "Add country to the user profile",
"overview": "Add a country attribute to the user based on their IP address.",
"categories": [
"enrich profile"
],
"description": "<p>This rule will add a <code>country</code> attribute to the user based on their ip address.</p>\n<p>Example geoip object:</p>\n<pre><code>\"geoip\": {\n \"country_code\": \"AR\",\n \"country_code3\": \"ARG\",\n \"country_name\": \"Argentina\",\n \"region\": \"05\",\n \"city\": \"Cordoba\",\n \"latitude\": -31.41349983215332,\n \"longitude\": -64.18109893798828,\n \"continent_code\": \"SA\",\n \"time_zone\": \"America/Argentina/Cordoba\"\n}\n</code></pre>",
"code": "function (user, context, callback) {\n if (context.request.geoip) {\n context.idToken['https://example.com/country'] = context.request.geoip.country_name;\n context.idToken['https://example.com/timezone'] = context.request.geoip.time_zone;\n }\n\n callback(null, user, context);\n}"
},
{
"id": "add-persistence-attribute",
"title": "Add persistent attributes to the user",
"overview": "Set the default color of a user's `user_metadata`.",
"categories": [
"enrich profile"
],
"description": "<p>This rule count set the default color (an example preference) to a user (using <code>user_metadata</code>).</p>",
"code": "function (user, context, callback) {\n user.user_metadata = user.user_metadata || {};\n user.user_metadata.color = user.user_metadata.color || 'blue';\n context.idToken['https://example.com/favorite_color'] = user.user_metadata.color;\n\n auth0.users.updateUserMetadata(user.user_id, user.user_metadata)\n .then(function(){\n callback(null, user, context);\n })\n .catch(function(err){\n callback(err);\n });\n}"
},
{
"id": "add-roles-from-sqlserver",
"title": "Add user roles from a SQL Server database",
"overview": "Query a SQL server database on each login and add a roles array to the user.",
"categories": [
"enrich profile"
],
"description": "<p>This rule will query a SQL server database on each login and add a <code>roles</code> array to the user.</p>\n<blockquote>\n <p>Note: you can store the connection string securely on Auth0 encrypted configuration. Also make sure when you call an external endpoint to open your firewall/ports to our IP address which you can find it in the rules editor. This happens when you query SQL Azure for example.</p>\n</blockquote>",
"code": "function (user, context, callback) {\n\n // Roles should only be set to verified users.\n if (!user.email || !user.email_verified) {\n return callback(null, user, context);\n }\n\n getRoles(user.email, (err, roles) => {\n if (err) return callback(err);\n\n context.idToken['https://example.com/roles'] = roles;\n\n callback(null, user, context);\n });\n\n // Queries a table by e-mail and returns associated 'Roles'\n function getRoles(email, done) {\n const connection = sqlserver.connect({\n userName: configuration.SQL_DATABASE_USERNAME,\n password: configuration.SQL_DATABASE_PASSWORD,\n server: configuration.SQL_DATABASE_HOSTNAME,\n options: {\n database: configuration.SQL_DATABASE_NAME,\n encrypt: true,\n rowCollectionOnRequestCompletion: true\n }\n }).on('errorMessage', (error) => {\n console.log(error.message);\n });\n\n const query = \"SELECT Email, Role FROM dbo.Role WHERE Email = @email\";\n\n connection.on('connect', (err) => {\n if (err) return done(new Error(err));\n\n const request = new sqlserver.Request(query, (err, rowCount, rows) => {\n if (err) return done(new Error(err));\n\n const roles = rows.map((row) => {\n return row[1].value;\n });\n\n done(null, roles);\n });\n\n request.addParameter('email', sqlserver.Types.VarChar, email);\n\n connection.execSql(request);\n });\n }\n}"
},
{
"id": "default-picture-null-avatars",
"title": "Default picture for null avatars",
"overview": "Set a default picture for null avatars.",
"categories": [
"enrich profile"
],
"description": "<p>This rule will set a default picture for null avatars via a rule for email-based logins:</p>",
"code": "function (user, context, callback) {\n if (user.picture.indexOf('cdn.auth0.com') > -1) {\n const url = require('url');\n const u = url.parse(user.picture, true);\n u.query.d = 'URL_TO_YOUR_DEFAULT_PICTURE_HERE';\n delete u.search;\n user.picture = url.format(u);\n }\n callback(null, user, context);\n}"
},
{
"id": "facebook-custom-picture",
"title": "Use a custom sized profile picture for Facebook connections",
"overview": "Set a custom sized profile picture for Facebook connections",
"categories": [
"enrich profile"
],
"description": "<p>This rule will set the <code>picture</code> to a custom size for users who login with Facebook.</p>",
"code": "function (user, context, callback) {\n if (context.connection === 'facebook') {\n const fbIdentity = _.find(user.identities, { connection: 'facebook' });\n // for more sizes and types of images that can be returned, see:\n // https://developers.facebook.com/docs/graph-api/reference/user/picture/\n const pictureType = 'large';\n context.idToken.picture = 'https://graph.facebook.com/v2.5/' + fbIdentity.user_id + '/picture?type=' + pictureType;\n }\n callback(null, user, context);\n}"
},
{
"id": "get-fullcontact-profile",
"title": "Enrich profile with FullContact",
"overview": "Get the user profile from FullContact using the email then add a new property to user_metadata.",
"categories": [
"enrich profile"
],
"description": "<p>This rule gets the user profile from FullContact using the e-mail (if available).</p>\n<p>If the information is immediately available (signaled by a <code>statusCode=200</code>), it adds a new property <code>fullContactInfo</code> to the user_metadata and returns. Any other conditions are ignored.</p>\n<p>See <a href=\"http://www.fullcontact.com/developer/docs/\">FullContact docs</a> for full details.</p>",
"code": "function (user, context, callback) {\n const FULLCONTACT_KEY = configuration.FULLCONTACT_KEY;\n const SLACK_HOOK = configuration.SLACK_HOOK_URL;\n\n const slack = require('slack-notify')(SLACK_HOOK);\n\n // skip if no email\n if (!user.email) return callback(null, user, context);\n\n // skip if fullcontact metadata is already there\n if (user.user_metadata && user.user_metadata.fullcontact) return callback(null, user, context);\n\n request.get('https://api.fullcontact.com/v2/person.json', {\n qs: {\n email: user.email,\n apiKey: FULLCONTACT_KEY\n },\n json: true\n }, (error, response, body) => {\n if (error || (response && response.statusCode !== 200)) {\n\n slack.alert({\n channel: '#slack_channel',\n text: 'Fullcontact API Error',\n fields: {\n error: error ? error.toString() : (response ? response.statusCode + ' ' + body : '')\n }\n });\n\n // swallow fullcontact api errors and just continue login\n return callback(null, user, context);\n }\n\n // if we reach here, it means fullcontact returned info and we'll add it to the metadata\n user.user_metadata = user.user_metadata || {};\n user.user_metadata.fullcontact = body;\n\n auth0.users.updateUserMetadata(user.user_id, user.user_metadata);\n context.idToken['https://example.com/fullcontact'] = user.user_metadata.fullcontact;\n return callback(null, user, context);\n });\n}"
},
{
"id": "get-getIP",
"title": "Enrich profile with the locations where the user logs in",
"overview": "Get the user locations based on IP address and add to the app_metadata in the geoip attribute",
"categories": [
"enrich profile"
],
"description": "<p>This rule gets the user locations based on the IP and is added to the <code>user_metadata</code> in the <code>geoip</code> attribute.</p>",
"code": "function (user, context, callback) {\n\n user.user_metadata = user.user_metadata || {};\n\n user.user_metadata.geoip = context.request.geoip;\n\n auth0.users.updateUserMetadata(user.user_id, user.user_metadata)\n .then(() => {\n context.idToken['https://example.com/geoip'] = context.request.geoip;\n callback(null, user, context);\n })\n .catch((err) => {\n callback(err);\n });\n}"
},
{
"id": "get-towerdata-profile",
"title": "Enrich profile with Towerdata (formerly RapLeaf)",
"overview": "Get user information from towerdata (formerly rapleaf) using email and add towerdata property to user profile.",
"categories": [
"enrich profile"
],
"description": "<p>This rule gets user information from towerdata using the e-mail (if available).</p>\n<p>If the information is immediately available (signaled by a <code>statusCode=200</code>), it adds a new property <code>towerdata</code> to the user profile and returns. Any other conditions are ignored.</p>\n<p>See http://docs.towerdata.com/#introduction-3 for full details.</p>",
"code": "function (user, context, callback) {\n\n //Filter by app\n //if(context.clientName !== 'AN APP') return callback(null, user, context);\n\n if (!user.email || !user.email_verified) {\n return callback(null, user, context);\n }\n\n request.get('https://api.towerdata.com/v5/td', {\n qs: {\n email: user.email,\n api_key: configuration.TOWERDATA_API_KEY\n },\n json: true\n },\n (err, response, body) => {\n if (err) return callback(err);\n\n if (response.statusCode === 200) {\n context.idToken['https://example.com/towerdata'] = body;\n }\n\n return callback(null, user, context);\n });\n}"
},
{
"id": "get-twitter-email",
"title": "Get email address from Twitter",
"overview": "Get user email address from Twitter.",
"categories": [
"enrich profile"
],
"description": "<p>Get email address from Twitter</p>\n<blockquote>\n <p>Note: Further configuration is needed to enable fetching user emails through your Twitter App.\n Take a look at <a href=\"https://dev.twitter.com/rest/reference/get/account/verify_credentials\">Twitter's doc</a> for specifics.</p>\n</blockquote>\n<p>The rule which makes the call to Twitter to retrieve the email is as follows. Do not forget to configure\n<code>consumerKey</code> and <code>consumerSecretKey</code> properly.</p>\n<p>This rule will not persist the returned email to the Auth0 user profile, but will return it to your application.</p>\n<p>If you want to persist the email, it will need to be done with app<em>metadata as described here: https://auth0.com/docs/rules/metadata-in-rules#updating-app</em>metadata.</p>\n<p>For example, you can save it under <code>app_metadata.social_email</code>.</p>",
"code": "function (user, context, callback) {\n // additional request below is specific to Twitter\n if (context.connectionStrategy !== 'twitter') {\n return callback(null, user, context);\n }\n\n const oauth = require('oauth-sign');\n const uuid = require('uuid');\n\n const url = 'https://api.twitter.com/1.1/account/verify_credentials.json';\n const consumerKey = configuration.TWITTER_CONSUMER_KEY;\n const consumerSecretKey = configuration.TWITTER_CONSUMER_SECRET_KEY;\n\n const twitterIdentity = _.find(user.identities, { connection: 'twitter' });\n const oauthToken = twitterIdentity.access_token;\n const oauthTokenSecret = twitterIdentity.access_token_secret;\n\n const timestamp = Date.now() / 1000;\n const nonce = uuid.v4().replace(/-/g, '');\n\n const params = {\n include_email: true,\n oauth_consumer_key: consumerKey,\n oauth_nonce: nonce,\n oauth_signature_method: 'HMAC-SHA1',\n oauth_timestamp: timestamp,\n oauth_token: oauthToken,\n oauth_version: '1.0'\n };\n\n params.oauth_signature = oauth.hmacsign('GET', url, params, consumerSecretKey, oauthTokenSecret);\n\n const auth = Object.keys(params).sort().map(function (k) {\n return k + '=\"' + oauth.rfc3986(params[k]) + '\"';\n }).join(', ');\n\n request.get(url + '?include_email=true', {\n headers: {\n 'Authorization': 'OAuth ' + auth\n },\n json: true\n }, (err, resp, body) => {\n if (resp.statusCode !== 200) {\n return callback(new Error('Error retrieving email from twitter: ' + body || err));\n }\n user.email = body.email;\n return callback(err, user, context);\n });\n}"
},
{
"id": "linkedin-original-picture",
"title": "Use the original sized profile picture for LinkedIn connections",
"overview": "Set the picture to the profile picture for users who login with LinkedIn",
"categories": [
"enrich profile"
],
"description": "<p>This rule will set the <code>picture</code> to the original sized profile picture for users who login with LinkedIn.</p>",
"code": "function (user, context, callback) {\n if (context.connection !== 'linkedin') {\n return callback(null, user, context);\n }\n\n const request = require('request');\n\n const liIdentity = _.find(user.identities, { connection: 'linkedin' });\n\n const options = {\n url: 'https://api.linkedin.com/v1/people/~/picture-urls::(original)?format=json',\n headers: {\n Authorization: 'Bearer ' + liIdentity.access_token\n },\n json: true\n };\n\n request(options, function (error, response, body) {\n if (error) return callback(error);\n if (response.statusCode !== 200) return callback(new Error(body));\n\n if (body.values && body.values.length >= 1) {\n context.idToken.picture = body.values[0];\n }\n\n return callback(null, user, context);\n });\n}"
},
{
"id": "remove-attributes",
"title": "Remove attributes from a user",
"overview": "Remove attributes from a user",
"categories": [
"enrich profile"
],
"description": "<p>Sometimes you don't need every attribute from the user. You can use a rule to delete attributes.</p>",
"code": "function (user, context, callback) {\n const blacklist = [ 'some_attribute' ];\n\n Object.keys(user).forEach(function(key) {\n if (blacklist.indexOf(key) > -1) {\n delete user[key];\n }\n });\n\n callback(null, user, context);\n}"
},
{
"id": "saml-attribute-mapping",
"title": "SAML Attributes mapping",
"overview": "In a SAML application customize the mapping between the Auth0 user and the SAML attributes",
"categories": [
"enrich profile",
"saml"
],
"description": "<p>If the application the user is logging in to is SAML (like Salesforce for instance), you can customize the mapping between the Auth0 user and the SAML attributes.\nBelow you can see that we are mapping <code>user_id</code> to the NameID, <code>email</code> to <code>http://schemas.../emailaddress</code>, etc.</p>\n<p>For more information about SAML options, see the <a href=\"https://docs.auth0.com/saml-configuration\">SAML Configuration docs</a>.</p>",
"code": "function (user, context, callback) {\n context.samlConfiguration.mappings = {\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\": \"user_id\",\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress\": \"email\",\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\": \"name\",\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/food\": \"user_metadata.favorite_food\",\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/address\": \"app_metadata.shipping_address\"\n };\n\n callback(null, user, context);\n}"
},
{
"id": "soap-webservice",
"title": "Roles from a SOAP Service",
"overview": "Show how to query a basic profile http binding SOAP web service for roles.",
"categories": [
"enrich profile"
],
"description": "<p>This rule shows how to query a basic profile http binding SOAP web service for roles and add those to the user.</p>",
"code": "function (user, context, callback) {\n const request = require('request');\n const xmldom = require('xmldom');\n const xpath = require('xpath');\n\n function getRoles(cb) {\n request.post({\n url: 'https://somedomain.com/RoleService.svc',\n body: '<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"><s:Body><GetRolesForCurrentUser xmlns=\"http://tempuri.org\"/></s:Body></s:Envelope>',\n headers: { 'Content-Type': 'text/xml; charset=utf-8',\n 'SOAPAction': 'http://tempuri.org/RoleService/GetRolesForCurrentUser' }\n }, function (err, response, body) {\n if (err) return cb(err);\n\n const parser = new xmldom.DOMParser();\n const doc = parser.parseFromString(body);\n const roles = xpath.select(\"//*[local-name(.)='string']\", doc).map(function(node) { return node.textContent; });\n return cb(null, roles);\n });\n }\n\n getRoles(function(err, roles) {\n if (err) return callback(err);\n\n context.idToken['https://example.com/roles'] = roles;\n\n callback(null, user, context);\n });\n}"
},
{
"id": "socure-fraudscore",
"title": "Detect Fraud Users",
"overview": "Get the fraud score from socure.com and store it on app_metadata.",
"categories": [
"enrich profile"
],
"description": "<p>This rule gets the fraud score from socure.com and store it on app_metadata.</p>",
"code": "function (user, context, callback) {\n // score fraudscore once (if it's already set, skip this)\n user.app_metadata = user.app_metadata || {};\n if (user.app_metadata.socure_fraudscore) return callback(null, user, context);\n\n if(!user.email) {\n // the profile doesn't have email so we can't query their api.\n return callback(null, user, context);\n }\n\n const request = require('request');\n\n // socurekey=A678hF8E323172B78E9&[email protected]&ipaddress=1.2.3.4&mobilephone=%2B12015550157\n request({\n url: 'https://service.socure.com/api/1/EmailAuthScore',\n qs: {\n email: user.email,\n socurekey: configuration.SOCURE_KEY,\n ipaddress: context.request.ip\n }\n }, function (err, resp, body) {\n if (err) return callback(null, user, context);\n if (resp.statusCode !== 200) return callback(null, user, context);\n const socure_response = JSON.parse(body);\n if (socure_response.status !== 'Ok') return callback(null, user, context);\n\n user.app_metadata = user.app_metadata || {};\n user.app_metadata.socure_fraudscore = socure_response.data.fraudscore;\n user.app_metadata.socure_confidence = socure_response.data.confidence;\n // \"details\":[\n // \"blacklisted\":{\n // \"industry\":\"Banking and Finance\",\n // \"reporteddate\":\"2014-07-02\",\n // \"reason\":\"ChargeBack Fraud\"\n // }\n // ]\n user.app_metadata.socure_details = socure_response.data.details;\n\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata)\n .then(function(){\n context.idToken['https://example.com/socure_fraudscore'] = user.app_metadata.socure_fraudscore;\n context.idToken['https://example.com/socure_confidence'] = user.app_metadata.socure_confidence;\n context.idToken['https://example.com/socure_details'] = user.app_metadata.socure_details;\n callback(null, user, context);\n })\n .catch(function(err){\n callback(null, user, context);\n });\n });\n}"
}
]
},
{
"name": "webhook",
"templates": [
{
"id": "aspnet-webapi",
"title": "Custom webhook with ASPNET WebApi2",
"overview": "Post variables sent to your Rule as a custom webhook in an ASP.NET WebApi application.",
"categories": [
"webhook"
],
"description": "<p>This rule shows how to post the variables sent to your Rule a custom webhook in an ASP.NET WebApi application. This is useful for situations where you want to enrich the User's profile with your internal ID before the JsonWebToken is created, or if you want to seamlessly register new users.</p>\n<p>In this example, we're going to get the internal UserId for your app, then persist it to the Auth0 UserProfile so we only have to make this request the first time a new user signs in.</p>\n<p>Within the snippet, the \"secretToken\" is a simple way to ensure that the communication is coming from Auth0. Just configure a random string for the Rule, and then check for that string in your WebApi request.</p>\n<p>In your WebApi code, complete whatever operations are necessary, then call <code>return Json(new { customId = USERSCUSTOMID });</code> to return the required JSON to the Rule.</p>\n<blockquote>\n <p>Note: Be sure to change the URL for the request to your website and controller, and make sure the controller is decorated with the <code>[HttpPost]</code> attribute.</p>\n</blockquote>\n<p>Contributed by Robert McLaws, AdvancedREI.com</p>",
"code": "function (user, context, callback) {\n user.app_metadata = user.app_metadata || {};\n if (user.app_metadata.customId) {\n console.log('Found ID!');\n return callback(null, user, context);\n }\n\n // You should make your requests over SSL to protect your app secrets.\n request.post({\n url: 'https://yourwebsite.com/auth0',\n json: {\n user: user,\n context: context,\n secretToken: configuration.YOURWEBSITE_SECRET_TOKEN,\n },\n timeout: 15000\n }, (err, response, body) => {\n if (err) return callback(new Error(err));\n\n user.app_metadata.customId = body.customId;\n context.idToken['https://example.com/custom_id'] = body.customId;\n\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata)\n .then(function(){\n callback(null, user, context);\n })\n .catch(function(err){\n callback(err);\n });\n });\n}"
},
{
"id": "creates-lead-salesforce",
"title": "Creates a new Lead in Salesforce on First Login",
"overview": "On first login call the Salesforce API to record the contact as a new Lead.",
"categories": [
"webhook"
],
"description": "<p>This rule will check if this is the first user login, and in that case will call Salesforce API to record the contact as a new Lead. It is using Salesforce REST APIs and the <code>resource owner</code> flow to obtain an <code>access_token</code>.</p>\n<p>The username you use to authenticate the API will appear as the <strong>creator</strong> of the lead.</p>\n<blockquote>\n <p>Note: this sample implements very basic error handling.</p>\n</blockquote>",
"code": "function (user, context, callback) {\n user.app_metadata = user.app_metadata || {};\n if (user.app_metadata.recordedAsLead) {\n return callback(null,user,context);\n }\n\n const MY_SLACK_WEBHOOK_URL = 'YOUR SLACK WEBHOOK URL';\n const slack = require('slack-notify')(MY_SLACK_WEBHOOK_URL);\n\n //Populate the variables below with appropriate values\n const SFCOM_CLIENT_ID = configuration.SALESFORCE_CLIENT_ID;\n const SFCOM_CLIENT_SECRET = configuration.SALESFORCE_CLIENT_SECRET;\n const USERNAME = configuration.SALESFORCE_USERNAME;\n const PASSWORD = configuration.SALESFORCE_PASSWORD;\n getAccessToken(\n SFCOM_CLIENT_ID,\n SFCOM_CLIENT_SECRET,\n USERNAME,\n PASSWORD,\n (response) => {\n if (!response.instance_url || !response.access_token) {\n slack.alert({\n channel: '#some_channel',\n text: 'Error Getting SALESFORCE Access Token',\n fields: {\n error: response\n }\n });\n\n return;\n }\n\n createLead(\n response.instance_url,\n response.access_token,\n (err, result) => {\n if (err || !result || !result.id) {\n slack.alert({\n channel: '#some_channel',\n text: 'Error Creating SALESFORCE Lead',\n fields: {\n error: err || result\n }\n });\n\n return;\n }\n\n user.app_metadata.recordedAsLead = true;\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata);\n });\n });\n\n //See http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_lead.htm\n function createLead(url, access_token, callback){\n //Can use many more fields\n const data = {\n LastName: user.name,\n Company: 'Web channel signups'\n };\n\n request.post({\n url: url + \"/services/data/v20.0/sobjects/Lead\",\n headers: {\n \"Authorization\": \"OAuth \" + access_token\n },\n json: data\n }, (err, response, body) => {\n return callback(err, body);\n });\n }\n\n //Obtains a SFCOM access_token with user credentials\n function getAccessToken(client_id, client_secret, username, password, callback) {\n request.post({\n url: 'https://login.salesforce.com/services/oauth2/token',\n form: {\n grant_type: 'password',\n client_id: client_id,\n client_secret: client_secret,\n username: username,\n password: password\n }}, (err, respose, body) => {\n return callback(JSON.parse(body));\n });\n }\n\n // don’t wait for the SF API call to finish, return right away (the request will continue on the sandbox)`\n callback(null, user, context);\n}"
},
{
"id": "intercom-user",
"title": "Record or update an Intercom User",
"overview": "Call the Intercom API to record/update an User.",
"categories": [
"webhook"
],
"description": "<p>This rule will call the Intercom API to create a new contact or update an existing contact's activity, whenever there is a signup or login with Auth0.</p>",
"code": "function (user, context, callback) {\n const request = require('request');\n const moment = require('moment-timezone');\n\n const data = {\n user_id: user.user_id,\n email: user.email,\n name: user.name,\n signed_up_at: moment(user.created_at).unix(),\n last_seen_ip : context.request.ip,\n last_seen_user_agent: context.request.userAgent,\n update_last_request_at: true,\n new_session: true\n };\n const accessToken = configuration.INTERCOM_ACCESS_TOKEN;\n\n request.post({\n url: 'https://api.intercom.io/users',\n headers: {\n Authorization: 'Bearer ' + accessToken,\n Accept: 'application/json'\n },\n json: data\n });\n // don’t wait for the Intercom API call to finish, return right away.\n callback(null, user, context);\n}"
},
{
"id": "mailgun",
"title": "Send emails through Mailgun",
"overview": "Send an email to an administrator on the first login of a user using Mailgun.",
"categories": [
"webhook"
],
"description": "<p>This rule will send an email to an administrator on the first login of a user using <a href=\"https://mailgun.com\">Mailgun</a>.</p>\n<p>We use a persistent property <code>SignedUp</code> to track whether this is the first login or subsequent ones.</p>",
"code": "function (user, context, callback) {\n user.app_metadata = user.app_metadata || {};\n\n if (user.app_metadata.signedUp) {\n return callback(null, user, context);\n }\n\n const request = require('request');\n\n request.post( {\n url: 'https://api.mailgun.net/v3/{YOUR MAILGUN ACCOUNT}/messages',\n auth:\n {\n user: 'api',\n pass: configuration.MAILGUN_API_KEY\n },\n form: {\n 'to': '[email protected]',\n 'subject': 'NEW SIGNUP',\n 'from': '[email protected]',\n 'text': 'We have got a new sign up from: ' + user.email + '.'\n }\n }, function(err, response, body) {\n if (err) return callback(err);\n if (response.statusCode !== 200) return callback(new Error('Invalid operation'));\n\n user.app_metadata.signedUp = true;\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata)\n .then(function(){\n callback(null, user, context);\n })\n .catch(function(err){\n callback(err);\n });\n });\n}"
},
{
"id": "mandrill",
"title": "Send email with Mandrill",
"overview": "Send email with Mandrill",
"categories": [
"webhook"
],
"description": "<p>This rule will send an email to an administrator on a user's first login. We use a persistent <code>signedUp</code> property to track whether this is the case or not.</p>\n<p>This rule assumes you've stored a secure value named <code>MANDRILL_API_KEY</code>, which contains your secret API key for Mandrill. It will be sent with each request.</p>\n<p>In the same way, other services such as <a href=\"http://docs.aws.amazon.com/ses/latest/APIReference/Welcome.html\">Amazon SES</a> and <a href=\"https://auth0.com/rules/sendgrid\">SendGrid</a> can be used.</p>\n<p>Make sure to change the sender and destination emails.</p>",
"code": "function (user, context, callback) {\n const request = require('request');\n\n user.app_metadata = user.app_metadata || {};\n // Only send an email when user signs up\n if (user.app_metadata.signedUp) {\n return callback(null, user, context);\n }\n\n // See https://mandrillapp.com/api/docs/messages.JSON.html#method=send\n const body = {\n key: configuration.MANDRILL_API_KEY,\n message: {\n subject: 'User ' + user.name + ' signed up to ' + context.clientName,\n text: 'Sent from an Auth0 rule',\n from_email: '[email protected]',\n from_name: 'Auth0 Rule',\n to: [\n {\n email: '[email protected]',\n type: 'to'\n }\n ],\n }\n };\n const mandrill_send_endpoint = 'https://mandrillapp.com/api/1.0/messages/send.json';\n\n request.post({url: mandrill_send_endpoint, form: body}, function (err, resp, body) {\n if (err) { return callback(err); }\n user.app_metadata.signedUp = true;\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata)\n .then(function(){\n callback(null, user, context);\n })\n .catch(function(err){\n callback(err);\n });\n });\n}"
},
{
"id": "mixpanel-track-event",
"title": "Tracks Logins in MixPanel",
"overview": "Send a Sign In event to MixPanel to track logins",
"categories": [
"webhook"
],
"description": "<p>This rule will send a <code>Sign In</code> event to MixPanel, and will include the application the user is signing in to as a property.</p>\n<p>See <a href=\"https://mixpanel.com/help/reference/http\">MixPanel HTTP API</a> for more information.</p>",
"code": "function (user, context, callback) {\n\n const mpEvent = {\n \"event\": \"Sign In\",\n \"properties\": {\n \"distinct_id\": user.user_id,\n \"token\": configuration.MIXPANEL_API_TOKEN,\n \"application\": context.clientName\n }\n };\n\n const base64Event = Buffer.from(JSON.stringify(mpEvent)).toString('base64');\n\n request.get({\n url: 'http://api.mixpanel.com/track/',\n qs: {\n data: base64Event\n }\n }, (err, res, body) => {\n // don’t wait for the MixPanel API call to finish, return right away (the request will continue on the sandbox)`\n callback(null, user, context);\n });\n}"
},
{
"id": "pusher",
"title": "Obtains a Pusher token for subscribing/publishing to private channels",
"overview": "Obtain a Pusher token for subscribing/publishing to private channels.",
"categories": [
"webhook"
],
"description": "<p>This rule will generate a [pusher.com] token that can be used to send and receive messages from private channels. See <a href=\"https://github.com/auth0/auth0-pusher\">a complete example here</a>.</p>",
"code": "function (user, context, callback) {\n const pusherKey = configuration.PUSHER_KEY;\n const pusherSecret = configuration.PUSHER_SECRET;\n\n if (context.request.query.channel && context.request.query.socket_id) {\n const pusherSigned = sign(pusherSecret, context.request.query.channel, context.request.query.socket_id);\n context.idToken['https://example.com/pusherAuth'] = pusherKey + \":\" + pusherSigned;\n }\n\n callback(null, user, context);\n\n function sign(secret, channel, socket_id) {\n const string_to_sign = socket_id + \":\" + channel;\n const sha = crypto.createHmac('sha256', secret);\n return sha.update(string_to_sign).digest('hex');\n }\n }"
},
{
"id": "send-events-keenio",
"title": "Send events to Keen",
"overview": "Send a signup event to Keen IO, tracked by the user.signedUp property",
"categories": [
"webhook"
],
"description": "<p>This rule is used to send a <code>signup</code> event to <a href=\"http://keen.io\">Keen IO</a></p>\n<p>The rule checks whether the user has already signed up before or not. This is tracked by the persistent <code>user.signedUp</code> property.\nIf the property is present, everything else is skipped. If not, then we POST a new event with some information to a <code>signups Collection</code> on Keen IO.</p>\n<p>Once enabled, events will be displayed on Keen IO dashboard:</p>\n<p><img src=\"http://puu.sh/7k4qN.png\" alt=\"\" /></p>",
"code": "function(user, context, callback) {\n if (context.stats.loginsCount > 1) {\n return callback(null, user, context);\n }\n\n const request = require('request');\n\n const MY_SLACK_WEBHOOK_URL = configuration.SLACK_WEBHOOK_URL;\n const slack = require('slack-notify')(MY_SLACK_WEBHOOK_URL);\n\n const projectId = configuration.KEEN_PROJ_ID;\n const writeKey = configuration.KEEN_WRITE_KEY;\n const eventCollection = 'signups';\n\n const keenEvent = {\n userId: user.user_id,\n name: user.name,\n ip: context.request.ip // Potentially any other properties in the user profile/context\n };\n\n request.post({\n url: 'https://api.keen.io/3.0/projects/' + projectId + '/events/' + eventCollection,\n headers: {\n 'Content-type': 'application/json',\n 'Authorization': writeKey,\n },\n body: JSON.stringify(keenEvent),\n },\n function (error, response, body) {\n if (error || (response && response.statusCode !== 200)) {\n slack.alert({\n channel: '#some_channel',\n text: 'KEEN API ERROR',\n fields: {\n error: error ? error.toString() : (response ? response.statusCode + ' ' + body : '')\n }\n });\n }\n });\n\n callback(null, user, context);\n}"
},
{
"id": "sendgrid",
"title": "Send emails through SendGrid",
"overview": "Send an email to an administrator through SendGrind on the first login of a user.",
"categories": [
"webhook"
],
"description": "<p>This rule will send an email to an administrator on the first login of a user.</p>\n<p>We use a persistent property <code>SignedUp</code> to track whether this is the first login or subsequent ones.</p>\n<p>In the same way you can use other services like <a href=\"http://docs.aws.amazon.com/ses/latest/APIReference/Welcome.html\">Amazon SES</a>, <a href=\"https://auth0.com/mandrill\">Mandrill</a> and few others.</p>",
"code": "function (user, context, callback) {\n user.app_metadata = user.app_metadata || {};\n\n if (user.app_metadata.signedUp) {\n return callback(null, user, context);\n }\n\n const request = require('request');\n\n request.post({\n url: 'https://api.sendgrid.com/api/mail.send.json',\n headers: {\n 'Authorization': 'Bearer ' + configuration.SENDGRID_API_KEY\n },\n form: {\n 'to': '[email protected]',\n 'subject': 'NEW SIGNUP',\n 'from': '[email protected]',\n 'text': 'We have got a new sign up from: ' + user.email + '.'\n }\n }, function (error, response, body) {\n if (error) return callback(error);\n if (response.statusCode !== 200) return callback(new Error('Invalid operation'));\n\n user.app_metadata.signedUp = true;\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata)\n .then(function () {\n callback(null, user, context);\n })\n .catch(function (err) {\n callback(err);\n });\n });\n}"
},
{
"id": "slack",
"title": "Slack Notification on User Signup",
"overview": "Slack notification on user signup.",
"categories": [
"webhook"
],
"description": "<p>This rule sends a message to a slack channel on every user signup.</p>",
"code": "function (user, context, callback) {\n // short-circuit if the user signed up already or is using a refresh token\n if (context.stats.loginsCount > 1 || context.protocol === 'oauth2-refresh-token') {\n return callback(null, user, context);\n }\n\n // get your slack's hook url from: https://slack.com/services/10525858050\n const SLACK_HOOK = configuration.SLACK_HOOK_URL;\n\n const slack = require('slack-notify')(SLACK_HOOK);\n const message = 'New User: ' + (user.name || user.email) + ' (' + user.email + ')';\n const channel = '#some_channel';\n\n slack.success({\n text: message,\n channel: channel\n });\n\n // don’t wait for the Slack API call to finish, return right away (the request will continue on the sandbox)`\n callback(null, user, context);\n}"
},
{
"id": "splunk-HEC-track-event",
"title": "Tracks Logins/SignUps with Splunk HEC",
"overview": "Send SignUp and Login events to Splunk's [HTTP Event Collector] (http://dev.splunk.com/view/event-collector/SP-CAAAE7F), including some contextual information of the user.",
"categories": [
"webhook"
],
"description": "<p>This rule will send a <code>SignUp</code> & <code>Login</code> events to Splunk's HTTP Event Collector, including some contextual information of the user: the application the user is signing in, client IP address, username, etc.</p>\n<p>We use a persistent property <code>SignedUp</code> to track whether this is the first login or subsequent ones.\nEvents will show up on the Splunk console shortly after user access:</p>\n<h4 id=\"setup\">Setup</h4>\n<p>In order to use this rule, you need to enable HTTP Event Collector (HEC) on your Splunk instance and get an HEC token. You can learn more how to do this <a href=\"http://dev.splunk.com/view/event-collector/SP-CAAAE7F\">here</a></p>\n<p>Below is a screenshot showing an SingUp event sent to Splunk Cloud.</p>\n<p><img src=\"https://cdn.auth0.com/website/rules/splunk-hec-rule.png\" alt=\"\" /></p>",
"code": "function (user, context, callback) {\n const request = require('request');\n\n user.app_metadata = user.app_metadata || {};\n const endpoint = 'https://http-inputs-mysplunkcloud.example.com:443/services/collector'; // replace with your Splunk HEC endpoint;\n\n //Add any interesting info to the event\n const hec_event = {\n event: {\n message: user.app_metadata.signedUp ? 'Login' : 'SignUp',\n application: context.clientName,\n clientIP: context.request.ip,\n protocol: context.protocol,\n userName: user.name,\n userId: user.user_id\n },\n source: 'auth0',\n sourcetype: 'auth0_activity'\n };\n\n request.post({\n url: endpoint,\n headers: {\n 'Authorization': 'Splunk ' + configuration.SPLUNK_HEC_TOKEN\n },\n strictSSL: true, // set to false if using a self-signed cert\n json: hec_event\n }, function(error, response, body) {\n if (error) return callback(error);\n if (response.statusCode !== 200) return callback(new Error('Invalid operation'));\n user.app_metadata.signedUp = true;\n auth0.users.updateAppMetadata(user.user_id, user.app_metadata)\n .then(function () {\n callback(null, user, context);\n })\n .catch(function (err) {\n callback(err);\n });\n });\n\n}"
},
{
"id": "update-firebase-user",
"title": "Update user profile identity in Firebase",
"overview": "Create or update identity information for a user profile stored in Firebase using the Firebase REST API.",
"categories": [
"webhook"
],
"description": "<p>This rule is used to create or update identity information for a user profile stored in Firebase using the Firebase REST API. The unique <code>user.user_id</code> is base64 encoded to provide a unique generated key for the user.</p>\n<p>Each time the user logs into the system, properties of their user profile can updated in Firebase to keep identity properties (like <code>name</code>, <code>email</code>, etc) in sync with authentication credentials.</p>\n<p>You can find more information in the Firebase API: <a href=\"https://www.firebase.com/docs/rest-api.html\">REST API</a></p>",
"code": "function (user, context, callback) {\n const request = require('request');\n\n const baseURL = configuration.FIREBASE_URL;\n const secret = configuration.FIREBASE_SECRET;\n const fb_id = Buffer.from(user.user_id).toString('base64');\n\n const fbIdentity = {\n identity: {\n user_id: user.user_id,\n email: user.email,\n name: user.name,\n nickname: user.nickname,\n picture: user.picture\n }\n };\n\n const putURL = baseURL + '/users/' + fb_id + '.json?auth=' + secret;\n request.put({\n url: putURL,\n json: fbIdentity\n },\n function(err, response, body) {\n if (err) return callback(err);\n return callback(null, user, context);\n });\n}"
},
{
"id": "zapier-new-login",
"title": "Trigger a Zap on Every User Login",
"overview": "Trigger a Zap on Every User Login to Zapier",
"categories": [
"webhook"
],
"description": "<p><strong>What is Zapier?</strong> <a href=\"http://zapier.com\">Zapier</a> is a tool for primarily non-technical users to connect together web apps. An integration between two apps is called a Zap. A Zap is made up of a Trigger and an Action. Whenever the trigger happens in one app, Zapier will automatically perform the action in another app.</p>\n<p><img src=\"https://cloudup.com/iGyywQuJqIb+\" alt=\"\" /></p>\n<p>This rule will call Zapier static hook every time a user logs in.</p>",
"code": "function (user, context, callback) {\n const request = require('request');\n\n const small_context = {\n appName: context.clientName,\n userAgent: context.request.userAgent,\n ip: context.request.ip,\n connection: context.connection,\n strategy: context.connectionStrategy\n };\n\n const payload_to_zap = _.extend({}, user, small_context);\n\n request.post({\n url : configuration.ZAP_HOOK_URL,\n json: payload_to_zap\n },\n function (err, response, body) {\n // swallow error\n callback(null, user, context);\n });\n}"
},
{
"id": "zapier-new-user",
"title": "Trigger a Zap on New Users",
"overview": "Trigger a Zap on every new user signup to Zapier.",
"categories": [
"webhook"
],
"description": "<p><strong>What is Zapier?</strong> <a href=\"http://zapier.com\">Zapier</a> is a tool for primarily non-technical users to connect together web apps. An integration between two apps is called a Zap. A Zap is made up of a Trigger and an Action. Whenever the trigger happens in one app, Zapier will automatically perform the action in another app.</p>\n<p><img src=\"https://cloudup.com/cgwZds8MjA7+\" alt=\"\" /></p>\n<p>This rule will call Zapier static hook every time a new user signs up.</p>",
"code": "function (user, context, callback) {\n // short-circuit if the user signed up already\n if (context.stats.loginsCount > 1) {\n return callback(null, user, context);\n }\n\n const request = require('request');\n\n const small_context = {\n appName: context.clientName,\n userAgent: context.request.userAgent,\n ip: context.request.ip,\n connection: context.connection,\n strategy: context.connectionStrategy\n };\n\n const payload_to_zap = _.extend({}, user, small_context);\n\n request.post({\n url: configuration.ZAP_HOOK_URL,\n json: payload_to_zap\n });\n\n // don’t wait for the Zapier WebHook call to finish, return right away (the request will continue on the sandbox)`\n callback(null, user, context);\n}"
}
]
},
{
"name": "multifactor",
"templates": [
{
"id": "duo-multifactor",
"title": "Multifactor with Duo Security",
"overview": "Trigger multifactor authentication with Duo Security when a condition is met.",
"categories": [
"multifactor"
],
"description": "<p>This rule is used to trigger multifactor authentication with <a href=\"http://duosecurity.com\">Duo Security</a> when a condition is met.</p>\n<p>Upon first login, the user can enroll the device.</p>\n<p>You need to create two <strong>integrations</strong> in <strong>Duo Security</strong>: one of type <strong>WebSDK</strong> and the other <strong>Admin SDK</strong>.</p>",
"code": "function (user, context, callback) {\n\n var CLIENTS_WITH_MFA = ['REPLACE_WITH_YOUR_CLIENT_ID'];\n // run only for the specified clients\n if (CLIENTS_WITH_MFA.indexOf(context.clientID) !== -1) {\n // uncomment the following if clause in case you want to request a second factor only from user's that have user_metadata.use_mfa === true\n // if (user.user_metadata && user.user_metadata.use_mfa){\n context.multifactor = {\n //required\n provider: 'duo',\n ikey: configuration.DUO_IKEY,\n skey: configuration.DUO_SKEY,\n host: configuration.DUO_HOST, // e.g.: 'api-XXXXXXXX.duosecurity.com',\n\n // optional, defaults to true. Set to false to force DuoSecurity every time.\n // See https://auth0.com/docs/multifactor-authentication/custom#change-the-frequency-of-authentication-requests for details\n allowRememberBrowser: false,\n\n // optional. Use some attribute of the profile as the username in DuoSecurity. This is also useful if you already have your users enrolled in Duo.\n // username: user.nickname\n };\n // }\n }\n\n callback(null, user, context);\n}"
},
{
"id": "guardian-multifactor-authorization-extension",
"title": "Multifactor with Auth0 Guardian + Authorization Extension",
"overview": "Guardian mfa + authorization extension working together.",
"categories": [
"multifactor",
"guardian"
],
"description": "<p>This rule is used to trigger multifactor authentication with Auth0 for one or more groups on the authorization extension.</p>\n<p>Upon first login, the user can enroll the device.</p>",
"code": "function (user, context, callback) {\n if (!user.app_metadata || !user.app_metadata.authorization ||\n !Array.isArray(user.app_metadata.authorization.groups)) {\n return callback(null, user, context);\n }\n\n const groups = user.app_metadata.authorization.groups;\n const GROUPS_WITH_MFA = {\n // Add groups that need MFA here\n // Example\n 'admins': true\n };\n\n const needsMFA = !!groups.find(function(group) {\n return GROUPS_WITH_MFA[group];\n });\n\n if (needsMFA){\n context.multifactor = {\n // required\n provider: 'guardian', //required\n\n // optional, defaults to true. Set to false to force Guardian authentication every time.\n // See https://auth0.com/docs/multifactor-authentication/custom#change-the-frequency-of-authentication-requests for details\n allowRememberBrowser: false\n };\n }\n\n callback(null, user, context);\n}"
},
{
"id": "guardian-multifactor-ip-range",
"title": "Multifactor when request comes from outside an IP range",
"overview": "Trigger multifactor authentication when IP is outside the expected range.",
"categories": [
"multifactor",
"guardian"
],
"description": "<p>This rule is used to trigger multifactor authentication when the requesting IP is from outside the corporate IP range.</p>",
"code": "function (user, context, callback) {\n const ipaddr = require('ipaddr.js');\n const corp_network = \"192.168.1.134/26\";\n const current_ip = ipaddr.parse(context.request.ip);\n\n if (!current_ip.match(ipaddr.parseCIDR(corp_network))) {\n context.multifactor = {\n provider: 'guardian',\n\n // optional, defaults to true. Set to false to force Guardian authentication every time.\n // See https://auth0.com/docs/multifactor-authentication/custom#change-the-frequency-of-authentication-requests for details\n allowRememberBrowser: false\n };\n }\n\n callback(null, user, context);\n}"
},
{
"id": "guardian-multifactor",
"title": "Multifactor with Auth0 Guardian",
"overview": "Trigger multifactor authentication with Auth0 when a condition is met.",
"categories": [
"multifactor",
"guardian"
],
"description": "<p>This rule is used to trigger multifactor authentication with Auth0 when a condition is met.</p>\n<p>Upon first login, the user can enroll the device.</p>",
"code": "function (user, context, callback) {\n //const CLIENTS_WITH_MFA = ['REPLACE_WITH_YOUR_CLIENT_ID'];\n\n // run only for the specified clients\n //if (CLIENTS_WITH_MFA.indexOf(context.clientID) !== -1) {\n\n // uncomment the following if clause in case you want to request a second factor only from user's that have user_metadata.use_mfa === true\n //if (user.user_metadata && user.user_metadata.use_mfa){\n context.multifactor = {\n // required\n provider: 'guardian',\n\n // optional, defaults to true. Set to false to force Guardian authentication every time.\n // See https://auth0.com/docs/multifactor-authentication/custom#change-the-frequency-of-authentication-requests for details\n allowRememberBrowser: false\n };\n //}\n //}\n\n callback(null, user, context);\n}"
},
{
"id": "mfa",
"title": "Multifactor Authentication",
"overview": "Trigger multifactor authentication when a condition is met.",
"categories": [
"multifactor"
],
"description": "<p>This rule is used to trigger multifactor authentication when a condition is met.</p>",
"code": "function (user, context, callback) {\n /*\n You can trigger MFA conditionally by checking:\n 1. Client ID:\n context.clientID === 'REPLACE_WITH_YOUR_CLIENT_ID'\n 2. User metadata:\n user.user_metadata.use_mfa\n */\n\n // if (<condition>) {\n context.multifactor = {\n provider: 'any',\n\n // optional, defaults to true. Set to false to force authentication every time.\n // See https://auth0.com/docs/multifactor-authentication/custom#change-the-frequency-of-authentication-requests for details\n allowRememberBrowser: false\n };\n //}\n\n callback(null, user, context);\n}"
}
]
},
{
"name": "guardian",
"templates": [
{
"id": "guardian-multifactor-authorization-extension",
"title": "Multifactor with Auth0 Guardian + Authorization Extension",
"overview": "Guardian mfa + authorization extension working together.",
"categories": [
"multifactor",
"guardian"
],
"description": "<p>This rule is used to trigger multifactor authentication with Auth0 for one or more groups on the authorization extension.</p>\n<p>Upon first login, the user can enroll the device.</p>",
"code": "function (user, context, callback) {\n if (!user.app_metadata || !user.app_metadata.authorization ||\n !Array.isArray(user.app_metadata.authorization.groups)) {\n return callback(null, user, context);\n }\n\n const groups = user.app_metadata.authorization.groups;\n const GROUPS_WITH_MFA = {\n // Add groups that need MFA here\n // Example\n 'admins': true\n };\n\n const needsMFA = !!groups.find(function(group) {\n return GROUPS_WITH_MFA[group];\n });\n\n if (needsMFA){\n context.multifactor = {\n // required\n provider: 'guardian', //required\n\n // optional, defaults to true. Set to false to force Guardian authentication every time.\n // See https://auth0.com/docs/multifactor-authentication/custom#change-the-frequency-of-authentication-requests for details\n allowRememberBrowser: false\n };\n }\n\n callback(null, user, context);\n}"
},
{
"id": "guardian-multifactor-ip-range",
"title": "Multifactor when request comes from outside an IP range",
"overview": "Trigger multifactor authentication when IP is outside the expected range.",
"categories": [
"multifactor",
"guardian"
],
"description": "<p>This rule is used to trigger multifactor authentication when the requesting IP is from outside the corporate IP range.</p>",
"code": "function (user, context, callback) {\n const ipaddr = require('ipaddr.js');\n const corp_network = \"192.168.1.134/26\";\n const current_ip = ipaddr.parse(context.request.ip);\n\n if (!current_ip.match(ipaddr.parseCIDR(corp_network))) {\n context.multifactor = {\n provider: 'guardian',\n\n // optional, defaults to true. Set to false to force Guardian authentication every time.\n // See https://auth0.com/docs/multifactor-authentication/custom#change-the-frequency-of-authentication-requests for details\n allowRememberBrowser: false\n };\n }\n\n callback(null, user, context);\n}"
},
{
"id": "guardian-multifactor",
"title": "Multifactor with Auth0 Guardian",
"overview": "Trigger multifactor authentication with Auth0 when a condition is met.",
"categories": [
"multifactor",
"guardian"
],
"description": "<p>This rule is used to trigger multifactor authentication with Auth0 when a condition is met.</p>\n<p>Upon first login, the user can enroll the device.</p>",
"code": "function (user, context, callback) {\n //const CLIENTS_WITH_MFA = ['REPLACE_WITH_YOUR_CLIENT_ID'];\n\n // run only for the specified clients\n //if (CLIENTS_WITH_MFA.indexOf(context.clientID) !== -1) {\n\n // uncomment the following if clause in case you want to request a second factor only from user's that have user_metadata.use_mfa === true\n //if (user.user_metadata && user.user_metadata.use_mfa){\n context.multifactor = {\n // required\n provider: 'guardian',\n\n // optional, defaults to true. Set to false to force Guardian authentication every time.\n // See https://auth0.com/docs/multifactor-authentication/custom#change-the-frequency-of-authentication-requests for details\n allowRememberBrowser: false\n };\n //}\n //}\n\n callback(null, user, context);\n}"
}
]
},
{
"name": "debugging",
"templates": [
{
"id": "requestbin",
"title": "Dump rule variables to RequestBin",
"overview": "Shows how to post the variables sent to your Rule to RequestBin to help troubleshoot rule issues",
"categories": [
"debugging"
],
"description": "<p>This rule shows how to post the variables sent to your Rule to <a href=\"https://requestbin.fullcontact.com\">RequestBin</a> to help troubleshoot issues with your Rules.</p>\n<blockquote>\n <p>Note: Auth0 provides <a href=\"https://auth0.com/docs/rules/current#how-to-debug-rules\">native mechanisms for debugging rules</a>. Should you still desire to send internal rule variables to a third-party service, you should deactivate this rule or comment out the code once you are finished troubleshooting.</p>\n</blockquote>\n<p>This rule shows how to post the variables sent to your Rule to https://requestbin.fullcontact.com to help troubleshoot issues with your Rules.</p>\n<p>You can run this rule by itself, or paste it into an existing rule.</p>",
"code": "function (user, context, callback) {\n const request = require('request');\n\n // https://auth0.com/docs/user-profile/user-profile-structure\n const user_whitelist = ['user_id', 'email', 'email_verified'];\n const user_filtered = _.pick(user, user_whitelist);\n\n // https://auth0.com/docs/rules/current/context\n const context_whitelist = ['clientID', 'connection', 'stats'];\n const context_filtered = _.pick(context, context_whitelist);\n\n request.post({\n url: 'https://requestbin.fullcontact.com/YourBinUrl',\n json: {\n user: user_filtered,\n context: context_filtered,\n },\n timeout: 15000\n }, function (err, response, body){\n if (err) return callback(err);\n return callback(null, user, context);\n });\n}"
}
]
},
{
"name": "saml",
"templates": [
{
"id": "saml-attribute-mapping",
"title": "SAML Attributes mapping",
"overview": "In a SAML application customize the mapping between the Auth0 user and the SAML attributes",
"categories": [
"enrich profile",
"saml"
],
"description": "<p>If the application the user is logging in to is SAML (like Salesforce for instance), you can customize the mapping between the Auth0 user and the SAML attributes.\nBelow you can see that we are mapping <code>user_id</code> to the NameID, <code>email</code> to <code>http://schemas.../emailaddress</code>, etc.</p>\n<p>For more information about SAML options, see the <a href=\"https://docs.auth0.com/saml-configuration\">SAML Configuration docs</a>.</p>",
"code": "function (user, context, callback) {\n context.samlConfiguration.mappings = {\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\": \"user_id\",\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress\": \"email\",\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\": \"name\",\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/food\": \"user_metadata.favorite_food\",\n \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/address\": \"app_metadata.shipping_address\"\n };\n\n callback(null, user, context);\n}"
},
{
"id": "saml-configuration",
"title": "Change SAML configuration",
"overview": "Change your SAML configuration.",
"categories": [
"saml"
],
"description": "<p>At some point you may want to add fields to your SAML Configuration. The way to do this is to add specific fields as done in the example code snippet below.\n<code>samlConfiguration</code> is an object that controls the behavior of the SAML and WS-Fed endpoints. Useful for advanced claims mapping and token enrichment (only available for SAMLP and WS-Fed protocol).</p>\n<p>To know more about SAML configuration options check <a href=\"https://auth0.com/docs/saml-configuration#configuration-options\">this documentation page</a>.</p>",
"code": "function (user, context, callback) {\n if (context.clientID !== '{YOUR_SAMLP_OR_WSFED_CLIENT_ID}') return callback(null, user, context);\n\n context.samlConfiguration = context.samlConfiguration || {};\n context.samlConfiguration.audience = \"urn:foo\";\n context.samlConfiguration.recipient = \"http://foo\";\n context.samlConfiguration.destination = \"http://foo\";\n context.samlConfiguration.lifetimeInSeconds = 3600;\n //context.samlConfiguration.mappings = {\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\": \"user_id\",\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress\": \"email\",\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\": \"name\",\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname\": \"given_name\",\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname\": \"family_name\",\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn\": \"upn\",\n // \"http://schemas.xmlsoap.org/claims/Group\": \"groups\"\n // };\n //context.samlConfiguration.nameIdentifierFormat = \"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\";\n //context.samlConfiguration.nameIdentifierProbes = [\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier\",\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress\",\n // \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\",\n // ];\n //context.samlConfiguration.signatureAlgorithm = \"rsa-sha1\";\n //context.samlConfiguration.digestAlgorithm = \"sha1\";\n //context.samlConfiguration.signResponse = false;\n //context.samlConfiguration.authnContextClassRef = \"urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified\";\n //context.samlConfiguration.mapIdentities = false;\n //context.samlConfiguration.mapUnknownClaimsAsIs = false;\n //context.samlConfiguration.passthroughClaimsWithNoMapping = true;\n //context.samlConfiguration.createUpnClaim = true;\n //context.samlConfiguration.logout = {\n // \"callback\": \"http://foo/logout\"\n // }\n\n //context.samlConfiguration.RelayState = \"foo=bar\"; // SAMLP protocol only\n //context.samlConfiguration.wctx = \"foo=bar\"; // WS-Fed protocol only\n\n callback(null, user, context);\n}"
}
]
},
{
"name": "default",
"templates": [
{
"id": "verify-user-email-with-password-reset",
"title": "Verify user email with password reset",
"overview": "Verify user email with password reset.",
"categories": [
"default"
],
"description": "<p>This rule will set the user's email as verified in the next login sequence after the password is reset successfully.</p>",
"code": "function (user, context, callback) {\n const request = require('request');\n const userApiUrl = auth0.baseUrl + '/users/';\n\n // This rule is only for Auth0 databases\n if (context.connectionStrategy !== 'auth0') {\n return callback(null, user, context);\n }\n\n if (user.email_verified || !user.last_password_reset) {\n return callback(null, user, context);\n }\n\n // Set email verified if a user has already updated his/her password\n request.patch({\n url: userApiUrl + user.user_id,\n headers: {\n Authorization: 'Bearer ' + auth0.accessToken\n },\n json: { email_verified: true },\n timeout: 5000\n },\n function(err, response, body) {\n // Setting email verified isn't propagated to id_token in this\n // authentication cycle so explicitly set it to true given no errors.\n context.idToken.email_verified = (!err && response.statusCode === 200);\n\n // Return with success at this point.\n return callback(null, user, context);\n });\n}"
}
]
}
]