diff --git a/sources/auth0/README.md b/sources/auth0/README.md new file mode 100644 index 0000000..84414fe --- /dev/null +++ b/sources/auth0/README.md @@ -0,0 +1,7 @@ +# Auth0 +Auth0 rapidly integrates authentication and authorization for web, mobile, and legacy applications so you can focus on your core business. + +You can send Auth0 logs to Segment using a Segment [Source Function](https://segment.com/docs/connections/functions/source-functions/). To get set up, take the following steps: +1. Log into your Auth0 account and follow [these instructions](https://auth0.com/docs/customize/log-streams/custom-log-streams) to create a webhook stream in Auth0. +2. Log in to Segment and create a Source Function there. +3. Provide Auth0 with the webhook URL Segment spun up for your Source Function. diff --git a/sources/auth0/handler.js b/sources/auth0/handler.js new file mode 100644 index 0000000..8664e5d --- /dev/null +++ b/sources/auth0/handler.js @@ -0,0 +1,172 @@ +/** + * Handle incoming HTTP request + * + * @param {FunctionRequest} request + * @param {FunctionSettings} settings + */ +async function onRequest(request, settings) { + const body = request.json(); + + //make event name easier to understand based on Auth0's log codes + //https://auth0.com/docs/deploy-monitor/logs/log-event-type-codes + const logCodes = { + "admin_update_launch": "Auth0 Update Launched", + "api_limit": "Rate Limit on the Authentication or Management APIs", + "cls": "Code/Link Sent", + "cs": "Code Sent", + "depnote": "Deprecation Notice", + "du": "Deleted User", + "f": "Failed Login", + "fapi": "Operation on API failed", + "fc": "Failed by Connector", + "fce": "Failed Change Email", + "fco": "Failed by CORS", + "fcoa": "Failed cross-origin authentication", + "fcp": "Failed Change Password", + "fcph": "Failed Post Change Password Hook", + "fcpn": "Failed Change Phone Number", + "fcpr": "Failed Change Password Request", + "fcpro": "Failed Connector Provisioning", + "fcu": "Failed Change Username", + "fd": "Failed Delegation", + "fdeac": "Failed Device Activation", + "fdeaz": "Failed Device Authorization Request", + "fdecc": "User Canceled Device Confirmation", + "fdu": "Failed User Deletion", + "feacft": "Failed Exchange", + "feccft": "Failed Exchange", + "fede": "Failed Exchange", + "fens": "Failed Exchange", + "feoobft": "Failed Exchange", + "feotpft": "Failed Exchange", + "fepft": "Failed Exchange", + "fepotpft": "Failed Exchange", + "fercft": "Failed Exchange", + "fertft": "Failed Exchange", + "ferrt": "Failed Exchange", + "fi": "Failed invite accept", + "flo": "Failed Logout", + "fn": "Failed Sending Notification", + "fp": "Failed Login (Incorrect Password)", + "fs": "Failed Signup", + "fsa": "Failed Silent Auth", + "fu": "Failed Login (Invalid Email/Username)", + "fui": "Failed users import", + "fv": "Failed Verification Email", + "fvr": "Failed Verification Email Request", + "gd_auth_failed": "MFA Auth failed", + "gd_auth_rejected": "MFA Auth rejected", + "gd_auth_succeed": "MFA Auth success", + "gd_enrollment_complete": "MFA enrollment complete", + "gd_otp_rate_limit_exceed": "Too many failures", + "gd_recovery_failed": "Recovery failed", + "gd_recovery_rate_limit_exceed": "Too many failures", + "gd_recovery_succeed": "Recovery success", + "gd_send_email": "Email Sent", + "gd_send_pn": "Push notification sent", + "gd_send_pn_failure": "Push notification sent", + "gd_send_sms": "SMS sent", + "gd_send_sms_failure": "SMS sent failures", + "gd_send_voice": "Voice call made", + "gd_send_voice_failure": "Voice call failure", + "gd_start_auth": "Second factor started", + "gd_start_enroll": "Enroll started", + "gd_start_enroll_failed": "Enrollment failed", + "gd_tenant_update": "Guardian tenant update", + "gd_unenroll": "Unenroll device account", + "gd_update_device_account": "Update device account", + "gd_webauthn_challenge_failed": "Enrollment challenge issued", + "gd_webauthn_enrollment_failed": "Enroll failed", + "limit_delegation": "Too Many Calls to /delegation", + "limit_mu": "Blocked IP Address", + "limit_wc": "Blocked Account", + "limit_sul": "Blocked Account", + "mfar": "MFA Required", + "mgmt_api_read": "Management API read Operation", + "pla": "Pre-login assessment", + "pwd_leak": "Breached password", + "resource_cleanup": "Refresh token excess warning", + "s": "Success Login", + "sapi": "Success API Operation", + "sce": "Success Change Email", + "scoa": "Success cross-origin authentication", + "scp": "Success Change Password", + "scph": "Success Post Change Password Hook", + "scpn": "Success Change Phone Number", + "scpr": "Success Change Password Request", + "scu": "Success Change Username", + "sd": "Success Delegation", + "sdu": "Success User Deletion", + "seacft": "Success Exchange", + "seccft": "Success Exchange", + "sede": "Success Exchange", + "sens": "Success Exchange", + "seoobft": "Success Exchange", + "seotpft": "Success Exchange", + "sepft": "Success Exchange", + "sercft": "Success Exchange", + "sertft": "Success Exchange", + "si": "Successful invite accept", + "signup_pwd_leak": "Breached password", + "srrt": "Success Revocation", + "slo": "Success Logout", + "ss": "Success Signup", + "ssa": "Success Silent Auth", + "sui": "Success users import", + "sv": "Success Verification Email", + "svr": "Success Verification Email Request", + "sys_os_update_end": "Auth0 OS Update Ended", + "sys_os_update_start": "Auth0 OS Update Started", + "sys_update_end": "Auth0 Update Ended", + "sys_update_start": "Auth0 Update Started", + "ublkdu": "User login block released", + "w": "Warnings During Login" + } + + let eventToSend = { + event: logCodes[body.data.type], + //assigns an identifier from Auth0's payload + anonymousId: body.data.client_id, + properties: { + ...body.data + } + }; + + //if payload is < Segment's limit of 32KB -> send it as is (https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/#max-request-size) + if (getRoughSizeOfObject(eventToSend) < 32) { + Segment.track(eventToSend); + } else { + //otherwise remove a portion and then send the pared down version + delete eventToSend.properties.details.request.auth.credentials.scopes; + Segment.track(eventToSend); + } + + + //checks size of outgoing payload + function getRoughSizeOfObject(object) { + let objectList = []; + let stack = [object]; + let bytes = 0; + + while (stack.length) { + let value = stack.pop(); + if (typeof value === 'boolean') { + bytes += 4; + } else if (typeof value === 'string') { + bytes += value.length * 2; + } else if (typeof value === 'number') { + bytes += 8; + } else if ( + typeof value === 'object' && + objectList.indexOf(value) === -1 + ) { + objectList.push(value); + for (let i in value) { + stack.push(value[i]); + } + } + } + //returns kilobytes - Segment's limit is 32KB + return bytes / 1000; + } +} diff --git a/sources/auth0/webhook-examples/failed_signup.json b/sources/auth0/webhook-examples/failed_signup.json new file mode 100644 index 0000000..a4c3209 --- /dev/null +++ b/sources/auth0/webhook-examples/failed_signup.json @@ -0,0 +1,76 @@ +{ + "payload": { + "body": { + "log_id": "90020221115155219994170187923660936391033852283976679442", + "data": { + "date": "2022-11-15T15:52:14.849Z", + "type": "fs", + "description": "Password is too weak", + "connection": "Username-Password-Authentication", + "connection_id": "con_rKY0IYI9hxvaMPxF", + "client_id": "Kx6QHMecjr7ItYzXjKKHNbwq1KWPQ7FB", + "client_name": "All Applications", + "ip": "35.167.74.121", + "user_agent": "unknown", + "details": { + "description": { + "rules": [ + { + "message": "At least %d characters in length", + "format": [ + 8 + ], + "code": "lengthAtLeast", + "verified": true + }, + { + "message": "Contain at least %d of the following %d types of characters:", + "code": "containsAtLeast", + "format": [ + 3, + 4 + ], + "items": [ + { + "message": "lower case letters (a-z)", + "code": "lowerCase", + "verified": true + }, + { + "message": "upper case letters (A-Z)", + "code": "upperCase", + "verified": false + }, + { + "message": "numbers (i.e. 0-9)", + "code": "numbers", + "verified": false + }, + { + "message": "special characters (e.g. !@#$%^&*)", + "code": "specialCharacters", + "verified": false + } + ], + "verified": false + } + ], + "verified": false + }, + "body": { + "client_id": "Kx6QHMecjr7ItYzXjKKHNbwq1KWPQ7FB", + "tenant": "dev-wrr7xwz1euw3aue3", + "email": "test@test.com", + "password": "*****", + "connection": "Username-Password-Authentication" + } + }, + "user_id": "", + "user_name": "test@test.com", + "strategy": "auth0", + "strategy_type": "database", + "log_id": "90020221115155219994170187923660936391033852283976679442" + } + } + } +} diff --git a/sources/auth0/webhook-examples/success_api_operation.json b/sources/auth0/webhook-examples/success_api_operation.json new file mode 100644 index 0000000..e984477 --- /dev/null +++ b/sources/auth0/webhook-examples/success_api_operation.json @@ -0,0 +1,178 @@ +{ + "payload": { + "body": { + "log_id": "90020221115155145216170187910137892172824607930531708946", + "data": { + "date": "2022-11-15T15:51:42.280Z", + "type": "sapi", + "description": "Runs all checks for a tenant", + "client_id": "Kx6QHMecjr7ItYzXjKKHNbwq1KWPQ7FB", + "client_name": "", + "ip": "35.167.74.121", + "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36", + "details": { + "request": { + "method": "post", + "path": "/api/v2/tenants/checks", + "query": {}, + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36", + "body": {}, + "channel": "https://manage.auth0.com/", + "ip": "35.167.74.121", + "auth": { + "user": { + "user_id": "auth0|63738f471560b8c9769a7952", + "name": "spencer.attick@segment.com", + "email": "spencer.attick@segment.com" + }, + "strategy": "jwt", + "credentials": { + "jti": "c1c64ce4ef3960b47978de84017d914e", + "scopes": [ + "create:actions", + "create:actions_log_sessions", + "create:client_credentials", + "create:client_grants", + "create:clients", + "create:connections", + "create:custom_domains", + "create:email_provider", + "create:email_templates", + "create:guardian_enrollment_tickets", + "create:integrations", + "create:log_streams", + "create:organization_connections", + "create:organization_invitations", + "create:organization_member_roles", + "create:organization_members", + "create:organizations", + "create:requested_scopes", + "create:resource_servers", + "create:roles", + "create:rules", + "create:shields", + "create:signing_keys", + "create:tenant_invitations", + "create:test_email_dispatch", + "create:users", + "delete:actions", + "delete:anomaly_blocks", + "delete:branding", + "delete:client_credentials", + "delete:client_grants", + "delete:clients", + "delete:connections", + "delete:custom_domains", + "delete:device_credentials", + "delete:email_provider", + "delete:email_templates", + "delete:grants", + "delete:guardian_enrollments", + "delete:integrations", + "delete:log_streams", + "delete:organization_connections", + "delete:organization_invitations", + "delete:organization_member_roles", + "delete:organization_members", + "delete:organizations", + "delete:owners", + "delete:requested_scopes", + "delete:resource_servers", + "delete:roles", + "delete:rules", + "delete:rules_configs", + "delete:shields", + "delete:tenant_invitations", + "delete:tenant_members", + "delete:tenants", + "delete:users", + "read:actions", + "read:anomaly_blocks", + "read:attack_protection", + "read:branding", + "read:checks", + "read:client_credentials", + "read:client_grants", + "read:client_keys", + "read:clients", + "read:connections", + "read:custom_domains", + "read:device_credentials", + "read:email_provider", + "read:email_templates", + "read:email_triggers", + "read:entity_counts", + "read:grants", + "read:guardian_factors", + "read:insights", + "read:integrations", + "read:log_streams", + "read:logs", + "read:mfa_policies", + "read:organization_connections", + "read:organization_invitations", + "read:organization_member_roles", + "read:organization_members", + "read:organizations", + "read:prompts", + "read:requested_scopes", + "read:resource_servers", + "read:roles", + "read:rules", + "read:rules_configs", + "read:shields", + "read:signing_keys", + "read:stats", + "read:tenant_invitations", + "read:tenant_members", + "read:tenant_settings", + "read:triggers", + "read:users", + "run:checks", + "update:actions", + "update:attack_protection", + "update:branding", + "update:client_credentials", + "update:client_grants", + "update:client_keys", + "update:clients", + "update:connections", + "update:custom_domains", + "update:email_provider", + "update:email_templates", + "update:email_triggers", + "update:guardian_factors", + "update:integrations", + "update:log_streams", + "update:mfa_policies", + "update:organization_connections", + "update:organizations", + "update:prompts", + "update:requested_scopes", + "update:resource_servers", + "update:roles", + "update:rules", + "update:rules_configs", + "update:shields", + "update:signing_keys", + "update:tenant_members", + "update:tenant_settings", + "update:triggers", + "update:users" + ] + } + } + }, + "response": { + "statusCode": 202, + "body": { + "id": "job_Agq730N3Ok2od5gJ" + } + } + }, + "user_id": "auth0|63738f471560b8c9769a7952", + "log_id": "90020221115155145216170187910137892172824607930531708946" + } + } + } +}