forked from auth0/rules
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rules.json
291 lines (291 loc) · 40 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
[
{
"name": "access control",
"templates": [
{
"title": "Allow Access during weekdays for a specific App",
"categories": [
"access control"
],
"description": "<p>This rule is used to prevent access during weekends for a specific app.</p>\n",
"code": "function (user, context, callback) {\n\n if (context.clientName === 'TheAppToCheckAccessTo') {\n var d = new 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}"
},
{
"title": "Active Directory group membership",
"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>\n",
"code": "function (user, context, callback) {\n var groupAllowed = 'group1';\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 callback(null, user, context);\n}"
},
{
"title": "Check last password reset",
"categories": [
"access control"
],
"description": "<p>This rule will check the last time that a user changed his or her account password.</p>\n",
"code": "function (user, context, callback) {\n\n function daydiff (first, second) {\n return (second-first)/(1000*60*60*24);\n }\n\n var 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\n callback(null, user, context);\n}"
},
{
"title": "Whitelist on the cloud",
"categories": [
"access control"
],
"description": "<p>This rule denies/grant access to users based on a list of emails stored in Dropbox.</p>\n",
"code": "function (user, context, callback) {\n request.get({\n url: 'https://dl.dropboxusercontent.com/u/21665105/users.txt'\n }, function (err, response, body) {\n var whitelist = body.split('\\r\\n');\n\n var 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}"
},
{
"title": "Set roles to a user",
"categories": [
"access control"
],
"description": "<p>This rule adds a Roles field to the user based on some pattern</p>\n",
"code": "function (user, context, callback) {\n // You can add a Role based on what you want\n // In this case I check domain\n var addRolesToUser = function(user, cb) {\n if (user.email.indexOf('@gonto.com') > -1) {\n cb(null, ['admin']);\n } else {\n cb(null, ['user']);\n }\n };\n\n addRolesToUser(user, function(err, roles) {\n if (err) {\n callback(err);\n } else {\n user.persistent.roles = roles;\n callback(null, user, context);\n }\n });\n}"
},
{
"title": "Whitelist for 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>\n",
"code": "function (user, context, callback) {\n //we just care about NameOfTheAppWithWhiteList\n //bypass this rule for every other app\n if(context.clientName !== 'NameOfTheAppWithWhiteList'){\n return callback(null, user, context);\n }\n\n var whitelist = [ 'user1@mail.com', 'user2@mail.com' ]; //authorized users\n var 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}"
},
{
"title": "Whitelist",
"categories": [
"access control"
],
"description": "<p>This rule will only allow access to users with specific email addresses.</p>\n",
"code": "function (user, context, callback) {\n var whitelist = [ 'user1@mail.com', 'user2@mail.com' ]; //authorized users\n var 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}"
},
{
"title": "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>\n",
"code": "function (user, context, callback) {\n\n // We check users only authenticated with 'fitbit'\n if(context.connection === 'fitbit'){\n\n var whitelist = [ 'user1', 'user2' ]; //authorized users\n var userHasAccess = whitelist.some(\n function (name) {\n return name === user.name;\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": [
{
"title": "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 persistede to the user). This is useful for cases where you want to enrich the user information for a specific application.</p>\n",
"code": "function (user, context, callback) {\n if (context.connection === 'company.com') {\n user.vip = true;\n }\n\n callback(null, user, context);\n}"
},
{
"title": "Add country to the user profile",
"categories": [
"enrich profile"
],
"description": "<p>This rule will add the <code>country</code> attribute to the user based on his ip address.</p>\n",
"code": "function (user, context, callback) {\n user.country = context.request.geoip.country;\n\n // Example geoip object:\n // \"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\n callback(null, user, context);\n}"
},
{
"title": "Add persistent attributes to the user",
"categories": [
"enrich profile"
],
"description": "<p>This rule count the amount of login for each user and store it as a persistent property (i.e. metadata).</p>\n",
"code": "function (user, context, callback) {\n user.loginCount = ++user.loginCount || 1;\n\n //this makes the property persistent\n user.persistent.loginCount = user.loginCount;\n\n callback(null, user, context);\n}"
},
{
"title": "Add user roles from a SQL Server database",
"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>\n",
"code": "function (user, context, callback) {\n getRoles(user.email, function(err, roles) {\n if (err) return callback(err);\n\n user.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 var connection = sqlserver.connect({\n userName: '<user_name>',\n password: '<password>',\n server: '<db_server_name>',\n options: {\n database: '<db_name>',\n encrypt: true,\n rowCollectionOnRequestCompletion: true\n }\n }).on('errorMessage', function (error) {\n console.log(error.message);\n });\n\n var query = \"SELECT Email, Role \" +\n \"FROM dbo.Role WHERE Email = @email\";\n\n connection.on('connect', function (err) {\n if (err) return done(new Error(err));\n\n var request = new sqlserver.Request(query, function (err, rowCount, rows) {\n if (err) return done(new Error(err));\n\n var roles = rows.map(function (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}"
},
{
"title": "Enrich profile with FullContact",
"categories": [
"enrich profile"
],
"description": "<p>This rule gets the user profile from FullContact using the e-mail (if available). If the information is immediately available (signaled by a <code>statusCode=200</code>), it adds a new property <code>fullContactInfo</code> to the user profile and returns. Any other conditions are ignored. See <a href=\"http://www.fullcontact.com/developer/docs/\">FullContact docs</a> for full details.</p>\n",
"code": "function (user, context, callback) {\n\n var fullContactAPIKey = 'YOUR FULLCONTACT API KEY';\n\n if(!user.email) {\n //the profile doesn't have email so we can't query fullcontact api.\n return callback(null, user, context);\n }\n\n request({\n url: 'https://api.fullcontact.com/v2/person.json',\n qs: {\n email: user.email,\n apiKey: fullContactAPIKey\n }\n }, function (e,r,b) {\n if(e) return callback(e);\n\n if(r.statusCode===200){\n user.fullContactInfo = JSON.parse(b);\n }\n\n return callback(null, user, context);\n });\n}"
},
{
"title": "Enrich profile with Rapleaf",
"categories": [
"enrich profile"
],
"description": "<p>This rule gets user information from <strong>rapleaf</strong> using the e-mail (if available). If the information is immediately available (signaled by a <code>statusCode=200</code>), it adds a new property <code>rapLeafInfo</code> to the user profile and returns. Any other conditions are ignored. See <a href=\"http://www.rapleaf.com/developers/personalization-api/\">RapLeaf docs</a> for full details.</p>\n",
"code": "function (user, context, callback) {\n\n //Filter by app\n //if(context.clientName !== 'AN APP') return callback(null, user, context);\n\n var rapLeafAPIKey = 'YOUR RAPLEAF API KEY';\n\n if(user.email){\n return callback(null, user, context);\n }\n\n request({\n url: 'https://personalize.rapleaf.com/v4/dr'\n qs: {\n email: user.email,\n api_key: rapLeafAPIKey\n }\n }, function(err, response, body){\n if(err) return callback(err);\n\n if(response.statusCode===200){\n user.rapLeafData = JSON.parse(body);\n }\n\n return callback(null, user, context);\n });\n\n}"
},
{
"title": "Store Google Refresh Token",
"categories": [
"enrich profile"
],
"description": "<p>In some scenarios, you might want to access Google APIs from your application. You do that by using the <code>access_token</code> stored on the <code>identities</code> array (<code>user.identities[0].access_token</code>). However <code>access_token</code>s have an expiration and in order to get a new one, you have to ask the user to login again. That's why Google allows asking for a <code>refresh_token</code> that can be used forever (until the user revokes it) to obtain new <code>access_tokens</code> without requiring the user to relogin.</p>\n<p>The way you ask for a <code>refresh_token</code> is by sending the <code>access_type=offline</code> as an extra parameter as <a href=\"https://docs.auth0.com/login-widget2#6\">explained here</a>.</p>\n<p>The only caveat is that Google will send you the <code>refresh_token</code> only once, and if you haven't stored it, you will have to ask for it again and add <code>approval_prompt=force</code> so the user explicitly consent again. Since this would be annoying from a user experience perspective, you should store the refresh token on Auth0 as a persistent property of the user, only if it there is a new one available.</p>\n<p>Here's the rule:</p>\n",
"code": "function (user, context, callback) {\n\n // if the user that just logged in has a refresh_token, persist it\n if (user.refresh_token) {\n user.persistent.refresh_token = user.refresh_token;\n }\n\n // IMPORTANT: for greater security, we recommend encrypting this value and decrypt on your application.\n // function encryptAesSha256 (password, textToEncrypt) {\n // var cipher = crypto.createCipher('aes-256-cbc', password);\n // var crypted = cipher.update(textToEncrypt, 'utf8', 'hex');\n // crypted += cipher.final('hex');\n // return crypted;\n // }\n\n callback(null, user, context);\n}"
},
{
"title": "Create a Google access_token using a Service Account",
"categories": [
"enrich profile"
],
"description": "<p>In some scenarios, you might want to access Google Admin APIs from your applications. Accesing those APIs require either a consent of the Google Apps administrator or creating a Service Account and obtain a token programatically without interactive consent. This rule create such token based on a service account and put it under <code>user.admin_access_token</code>. </p>\n<p>To create a service account go to Google API Console, create a new Client ID and choose Service Account</p>\n<p><img src=\"https://cloudup.com/cpvhC6n9xW9+\" width=\"420\"></p>\n<p>You will get the key that you would have to convert to PEM and remove the passphrase using this command</p>\n<p> openssl pkcs12 -in yourkey.p12 -out yourkey.pem -nocerts -nodes</p>\n<p>Login to Google Apps Admin and go to <a href=\"https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients\">https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients</a> (Security -> Advanced Settings -> Manage OAuth Client Access)\nEnter</p>\n<p><img src=\"https://cloudup.com/c0Nq5NWRFaQ+\" width=\"620\"></p>\n<p>Enter the Client ID created on the previous step and the scope you want to allow access to.</p>\n<ul>\n<li><code>KEY</code>: the string representation of the key (open the PEM and replace enters with \\n to make it one line).</li>\n<li><code>GOOGLE_CLIENT_ID_EMAIL</code>: this is the email address of the service account created (NOT the Client ID).</li>\n<li><code>SCOPE</code>: the scope you want access to. Full list of scopes <a href=\"https://developers.google.com/admin-sdk/directory/v1/guides/authorizing\">https://developers.google.com/admin-sdk/directory/v1/guides/authorizing</a>.</li>\n<li><code>ADMIN_EMAIL</code>: a user of your Google Apps domain that this rule would impersonate.</li>\n</ul>\n<blockquote>\n<p>NOTE: the Google access_token will last 1 hour, so you will have to either force a re-login or use a refresh token to trigger a token refresh on Auth0 and hence the rule running again.</p>\n<p>NOTE 2: you might want to be careful what scopes you ask for and where the access_token will be used. For instance, if used from a JavaScript application, a low-privilieged user might grab the token and do API calls that you wouldn't allow.</p>\n</blockquote>\n<p>Here's the rule:</p>\n",
"code": "function (user, context, callback) {\n\n // this is the private key you downloaded from your service account.\n // make sure you remove the password from the key and convert it to PEM using the following\n // openssl pkcs12 -in yourkey.p12 -out yourkey.pem -nocerts -nodes\n // finally, you should put this as a configuration encrypted in Auth0\n var KEY = '....RSA private key downloaded from service account...'; \n\n // this is the email address of the service account created (NOT the Client ID)\n var GOOGLE_CLIENT_ID_EMAIL = '.....@developer.gserviceaccount.com';\n\n // the scope you want access to. Full list of scopes https://developers.google.com/admin-sdk/directory/v1/guides/authorizing\n var SCOPE = 'https://www.googleapis.com/auth/admin.directory.user.readonly';\n\n // a user of your Google Apps domain that this rule would impersonate\n var ADMIN_EMAIL = 'foo@corp.com';\n\n var token = jwt.sign({ scope: SCOPE, sub: ADMIN_EMAIL }, KEY, { audience: \"https://accounts.google.com/o/oauth2/token\", issuer: GOOGLE_CLIENT_ID_EMAIL, expiresInMinutes: 60, algorithm: 'RS256'});\n\n request.post({ url: 'https://accounts.google.com/o/oauth2/token', form: { grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion: token } }, function(err, resp, body) {\n if (err) return callback(null, user, context);\n var result = JSON.parse(body);\n if (result.error) {\n console.log(body);\n // log and swallow\n return callback(null, user, context);\n }\n\n user.admin_access_token = result.access_token;\n callback(null, user, context);\n });\n\n}"
},
{
"title": "Querystring",
"categories": [
"enrich profile"
],
"description": "<p>This rule shows how to check for variables in the <code>querystring</code>. As an example, the snippet below checks if the login transaction includes a query variable called <code>some_querystring</code> with a value <code>whatever</code> and if it does, it will add an attribute to the user profile.</p>\n<p>An example of typical authorization URL:</p>\n<p>The <code>context.request.query</code> object is parsed using the <code>querystring</code> module <a href=\"http://nodejs.org/api/querystring.html\">http://nodejs.org/api/querystring.html</a></p>\n<blockquote>\n<p>Note: this rule works with any protocols supported by Auth0. For example, WS-Fed would be something like: <code>https://YOURS.auth0.com/wsfed?wtrealm=YOUR_APP_REALM&whr=urn:google-oauth2&some_querystring=whatever</code></p>\n</blockquote>\n",
"code": "https://YOURS.auth0.com/authorize?response_type=code\n &redirect_uri=CALLBACK\n &connection=google-oauth2\n &client_id=YOUR_CLIENTID\n &some_querystring=whatever"
},
{
"title": "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>\n",
"code": "function (user, context, callback) {\n delete user.some_attribute;\n\n // another option would be to define a whitelist of attributes you want,\n // instead of delete the ones you don't want\n /*\n var whitelist = ['email', 'name', 'identities'];\n Object.keys(user).forEach(function(key) {\n console.log(whitelist.indexOf(key));\n if (whitelist.indexOf(key) === -1) delete user[key];\n });\n */\n\n callback(null, user, context);\n}"
},
{
"title": "SAML Attributes mapping",
"categories": [
"enrich profile"
],
"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 attrbiutes.\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, look at <a href=\"https://docs.auth0.com/saml-configuration\">https://docs.auth0.com/saml-configuration</a>.</p>\n",
"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 };\n\n callback(null, user, context);\n}"
},
{
"title": "Roles from a SOAP Service",
"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>\n",
"code": "function (user, context, callback) {\n function getRoles(callback) {\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 callback(err);\n\n var parser = new xmldom.DOMParser();\n var doc = parser.parseFromString(body);\n var roles = xpath.select(\"//*[local-name(.)='string']\", doc).map(function(node) { return node.textContent; });\n return callback(null, roles);\n });\n }\n\n getRoles(user.email, function(err, roles) {\n if (err) return callback(err);\n\n user.roles = roles;\n\n callback(null, user, context);\n });\n}"
}
]
},
{
"name": "webhook",
"templates": [
{
"title": "Custom webhook with ASP.NET WebApi2",
"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 type in a random string into 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>\n",
"code": "function (user, context, callback) { \n if (user.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: \";ojhsajk;h;Kh:Jh\",\n },\n timeout: 15000\n }, function(err, response, body){\n if (err) return callback(new Error(err));\n user.persistent.customId = body.customId;\n return callback(null, user, context);\n });\n}"
},
{
"title": "Creates a new Lead in Salesforce on First Login",
"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>. 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>\n",
"code": "function (user, context, callback) {\n\n if (user.recordedAsLead){\n return callback(null,user,callback);\n }\n\n getAccessToken(SFCOM_CLIENT_ID, SFCOM_CLIENT_SECRET, USERNAME, PASSWORD,\n function(e,r) {\n if (e) return callback(e);\n\n createLead( r.instance_url, r.access_token, function (e, result) {\n if (e) return callback(e);\n user.persistent.recordedAsLead = true;\n return callback(null,user,context);\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\n //Can use many more fields\n var 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 \"Content-type\": \"application/json\"\n },\n body: JSON.stringify(data)\n }, function(e,r,b) {\n if (e) return callback(e);\n return callback(null,b);\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 }}, function(e,r,b) {\n if (e) return callback(e);\n return callback(null,JSON.parse(b));\n });\n }\n}"
},
{
"title": "Tracks Logins in MixPanel",
"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. See <a href=\"https://mixpanel.com/help/reference/http\">MixPanel HTTP API</a> for more information.</p>\n",
"code": "function (user, context, callback) {\n\n var mpEvent = {\n \"event\": \"Sign In\",\n \"properties\": {\n \"distinct_id\": user.user_id,\n \"token\": \"{REPLACE_WITH_YOUR_MIXPANEL_TOKEN}\",\n \"application\": context.clientName\n }\n };\n\n var base64Event = new Buffer(JSON.stringify(mpEvent)).toString('base64');\n\n request.get({\n url: 'http://api.mixpanel.com/track/}',\n qs: {\n data: base64Event\n }\n }, function(e,r,b){\n callback(null,user,context);\n });\n}"
},
{
"title": "Obtains 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>\n",
"code": "function (user, context, callback) {\n\n var pusherKey='YOUR PUSHER KEY';\n var pusherSecret = '{YOUR PUSHER SECRET}';\n\n if( context.request.query.channel && context.request.query.socket_id)\n {\n user.pusherAuth = pusherKey + \":\" + sign(pusherSecret, context.request.query.channel, context.request.query.socket_id);\n }\n\n callback(null, user, context);\n\n function sign(secret, channel, socket_id)\n {\n var string_to_sign = socket_id+\":\"+channel;\n var sha = crypto.createHmac('sha256',secret);\n return sha.update(string_to_sign).digest('hex');\n }\n}"
},
{
"title": "Send events to Keen.io",
"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. If the property is present, everything else is skipped.\nIf 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:\n<img src=\"http://puu.sh/7k4qN.png\" alt=\"\"></p>\n",
"code": "function(user, context, callback) {\n\n if(user.signedUp){\n return callback(null, user, context);\n }\n\n var writeKey = 'YOUR KEEN IO WRITE KEY';\n var projectId = 'YOUR KEEN IO PROJECT ID';\n var eventCollection = 'signups';\n\n var 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 method: 'POST',\n url: 'https://api.keen.io/3.0/projects/' + projectId + '/events/' + eventCollection + '?api_key=' + writeKey,\n headers: {\n 'Content-type': 'application/json',\n },\n body: JSON.stringify(keenEvent),\n },\n function (e, r, body) {\n if( e ) return callback(e,user,context);\n //We assume everything went well\n user.persistent.signedUp = true;\n return callback(null, user, context);\n });\n\n}"
},
{
"title": "Send emails through SendGrid",
"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://mandrillapp.com/api/docs/\">Mandrill</a> and few others.</p>\n",
"code": "function(user, context, callback) {\n if (!user.persistent.signedUp) {\n return callback(null, user, context);\n }\n\n request.post( {\n url: 'https://api.sendgrid.com/api/mail.send.json',\n form: {\n 'api_user': 'YOUR SENDGRID API USER',\n 'api_key': 'YOUR SENDGRID API PASS',\n 'to': 'admin@myapp.com',\n 'subject': 'NEW SIGNUP',\n 'from': 'admin@myapp.com',\n 'text': 'We have got a new sign up from: ' + user.email + '.'\n }\n }, function(e,r,b) {\n if (e) return callback(e);\n if (r.statusCode !== 200) return callback(new Error('Invalid operation'));\n user.persistent.signedUp = true;\n callback(null, user, context);\n });\n}"
},
{
"title": "Tracks Logins/SignUps with Splunk",
"categories": [
"webhook"
],
"description": "<p>This rule will send a <code>SignUp</code> & <code>Login</code> events to Splunk, 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.</p>\n<p>Events will show up on the Splunk console shortly after user access:</p>\n<p><img src=\"http://puu.sh/7R1EW.png\" alt=\"\"></p>\n",
"code": "function(user, context, callback) {\n\n var splunkBaseUrl = 'YOUR SPLUNK SERVER, like: https://your server:8089';\n\n //Add any interesting info to the event\n var event = {\n message: user.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\n request.post( {\n url: splunkBaseUrl + '/services/receivers/simple',\n auth: {\n 'user': 'YOUR SPLUNK USER',\n 'pass': 'YOUR SPLUNK PASSWORD',\n },\n json: event,\n qs: {\n 'source': 'auth0',\n 'sourcetype': 'auth0_activity'\n }\n }, function(e,r,b) {\n if (e) return callback(e);\n if (r.statusCode !== 200) return callback(new Error('Invalid operation'));\n user.persistent.signedUp = true;\n return callback(e, user, context);\n });\n\n}"
},
{
"title": "Update user profile identity in Firebase",
"categories": [
"webhook"
],
"description": "<p>This rule is used to create or update identity information for a user profile\nstored in Firebase using the Firebase REST API. The unique <code>user.user_id</code> is\nbase64 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\nprofile can updated in Firebase to keep identity properties (like\nname, email, 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>\n",
"code": "function (user, context, callback) {\n\n var baseURL = configuration.FIREBASE_URL;\n var secret = configuration.FIREBASE_SECRET;\n var fb_id = new Buffer(user.user_id).toString('base64');\n\n var 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 var 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}"
},
{
"title": "Trigger a Zap on Every User Login",
"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>\n",
"code": "function (user, context, callback) {\n var ZAP_HOOK_URL = 'REPLACE_ME';\n\n var small_context = {\n appName: context.clientName,\n userAgent: context.userAgent,\n ip: context.ip,\n connection: context.connection,\n strategy: context.connectionStrategy\n };\n var payload_to_zap = extend({}, user, small_context);\n request.post({\n url: ZAP_HOOK_URL,\n json: payload_to_zap\n },\n function (err, response, body) {\n // swallow error\n callback(null, user, context);\n });\n\n function extend(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i],\n keys = Object.keys(source);\n\n for (var j = 0; j < keys.length; j++) {\n var name = keys[j];\n target[name] = source[name];\n }\n }\n return target;\n }\n}"
},
{
"title": "Trigger a Zap on New Users",
"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>\n",
"code": "function (user, context, callback) {\n var ZAP_HOOK_URL = 'REPLACE_ME';\n\n // short-circuit if the user signed up already\n if (user.signed_up) return callback(null, user, context);\n\n var small_context = {\n appName: context.clientName,\n userAgent: context.userAgent,\n ip: context.ip,\n connection: context.connection,\n strategy: context.connectionStrategy\n };\n var payload_to_zap = extend({}, user, small_context);\n request.post({\n url: ZAP_HOOK_URL,\n json: payload_to_zap\n },\n function (err, response, body) {\n // swallow error\n // mark the user as `signed_up` so next time the rule does not execute\n user.persistent.signed_up = true;\n callback(null, user, context);\n });\n\n function extend(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i],\n keys = Object.keys(source);\n\n for (var j = 0; j < keys.length; j++) {\n var name = keys[j];\n target[name] = source[name];\n }\n }\n return target;\n }\n}"
}
]
},
{
"name": "multifactor",
"templates": [
{
"title": "Multifactor with Duo Security",
"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>\n",
"code": "function (user, context, callback) {\n\n //if (condition == ..) { }\n context.multifactor = {\n\n //required\n provider: 'duo',\n ikey: 'DIXBMN...LZO8IOS8',\n skey: 'nZLxq8GK7....saKCOLPnh',\n host: 'api-3....049.duosecurity.com',\n\n //optional, force DuoSecurity everytime this rule runs. Defaults false.\n ignoreCookie: true,\n\n //optional\n //Use some attribute of the profile as the username in DuoSecurity.\n //This is also useful if you already have your users enrolled in Duo.\n username: user.nickname\n\n //optional\n //Admin credentials. If you provide an Admin SDK type of credentials\n //auth0 will update the realname and email in DuoSecurity.\n admin: {\n ikey: 'DIAN...NV6UM',\n skey: 'YL8OVzvoeeh...I1uiYrKoHvuzHnSRj'\n },\n };\n\n callback(null, user, context);\n}"
},
{
"title": "Multifactor with Google Authenticator",
"categories": [
"multifactor"
],
"description": "<p>This rule is used to trigger multifactor authentication with Google Authenticator when a condition is met.</p>\n<p>Upon first login, the user can enroll the device by scanning a QR code. Subsequent logins will ask for the Google Authenticator code.</p>\n<p>To reset Google Authenticator for a user, you can go to Users, search for the specific user and click on Actions -> Multifactor.</p>\n",
"code": "function (user, context, callback) {\n\n //if (condition == ..) { }\n context.multifactor = {\n provider: 'google-authenticator'\n };\n\n callback(null, user, context);\n}"
}
]
},
{
"name": "debugging",
"templates": [
{
"title": "Dump rule variables to RequestB.in",
"categories": [
"debugging"
],
"description": "<p>This rule shows how to post the variables sent to your Rule to <a href=\"http://RequestB.in\">http://RequestB.in</a> to help troubleshoot issues with your Rules.</p>\n<p>You can run this rule by itself, or paste it into an existing rule. Once the rule has posted data to RequestB.in, you can use a site like <a href=\"http://bodurov.com/JsonFormatter/\">http://bodurov.com/JsonFormatter/</a> to more easily visualize the data.</p>\n<blockquote>\n<p>Note: You should deactivate this rule or comment out the code once you are finished troubleshooting.</p>\n</blockquote>\n<p>Contributed by Robert McLaws, AdvancedREI.com</p>\n",
"code": "function (user, context, callback) {\n request.post({\n url: 'http://requestb.in/YourBinUrl',\n json: {\n user: user,\n context: context,\n },\n timeout: 15000\n }, function(err, response, body){\n if (err) return callback(new Error(err));\n return callback(null, user, context);\n });\n}"
}
]
}
]