1 Auth0 Integration to associate users Shared by Darin Pesnell, Iron Works Church 4 years ago General Intermediate For our church, we wanted the ability for users to login to Rock with either passwordless authentication, or with Google Social.We decided on the Auth0 integration published in the Hero Guide as our choice for the solution.Setting it up was simple when following the instructions; however, we noticed that when logging in through Auth0, Rock created a new user instead of associating the login with an existing user.We saw that a unique AUTH0_email|XXXXXXXXXXX ID would be associated with the new users' account:To resolve this, we configured a "post user registration" action in the auth0 dashboard under "Actions" -> "flows" -> "post user registration".We put in the Node.js code a very simple HTTPS call to an AWS Lambda function running Python (my language of choice) to make some API calls to Rock:/** @type {PostUserRegistrationAction} */ module.exports = async (event, context) => { const https = require('https'); const data = JSON.stringify(event); const options = { hostname: "xxxxxxxx.execute-api.us-east-1.amazonaws.com", port: 443, path: '/default/RockAssociateUser', method: 'POST', headers: { 'Content-Type': 'application/json', }, } const req = https.request(options, (res) => { console.log(`statusCode: ${res.statusCode}`) res.on('data', (d) => { process.stdout.write(d) }) }) req.on('error', (error) => { console.error(error) }) req.write(data) req.end() return{}; }; Inside of the AWS Lambda job, we have the following python function:import json import boto3 import requests sns = boto3.client('sns') auth_key = "XXXXXXXXXX" baseurl = "https://rockdev.somechurch.com/api/" headers = {"authorization-token": auth_key, "Content-Type": "application/json"} def lambda_handler(event, context): data = json.loads(event["body"]) print(data ) email = data["user"]["email"] auth0ID = "AUTH0_email|" + data["user"]["id"] userID = findPerson(email) updateAuth(userID, auth0ID) #sns.publish(TopicArn=sns_topic, Message=json.dumps(event["body"])) return { 'statusCode': 200, 'body': json.dumps("Completed") } def findPerson(email): r = requests.get(baseurl + "/People?$filter=Email%20eq%20'" + email + "'&$select=Id", headers=headers) r = r.json() return(r[0]["Id"]) def updateAuth(userID, auth0ID): data = {"EntityTypeId": 665, "UserName": auth0ID, "IsConfirmed": "true", "PersonId": int(userID)} data = json.dumps(data) r =requests.post(baseurl + "UserLogins", data=data, headers=headers) r = r.json() print(r)The Python code has 3 functionsfindPersonThis function locates the ID of the Rock user based on their email address (retrieves the earliest record created)updateAuthThis function creates a userLogin with the Auth0 ID so that the Auth0 account is properly associated with the user.If a user's email is not present in Rock a new account will be created. Also, if there are multiple accounts with the same email, it will pick the first one it finds so you need to stay on top of merging duplicate records. I hope someone finds this helpful.
Tataihono Nikora5 Months AgoApologies the import statement at the beginning should be a require. const axios = require('axios')
Tataihono Nikora5 Months AgoHey Darin. Thanks for setting this up. I created a node only version of this script to be run directly by Auth0. Let me know your thoughts: import axios from "axios"; /** * Creates an Axios client instance for interacting with the API. * * @param {string} url - The API URL * @param {string} token - The API token for authorization. * @returns {import("axios").AxiosInstance} An Axios client instance configured with the provided token. */ const createClient = (url, token) => { return axios.create({ baseURL: url, timeout: 60000, headers: { "Authorization-Token": `${token}`, "Content-Type": "application/json", }, }); }; /** * Finds a person in the API by email. * * @param {import("axios").AxiosInstance} client - The Axios client instance. * @param {string} email - The email address of the person to find. * @returns {Promise<number|undefined>} The ID of the person if found, or null if not found. */ const findRockPersonId = async (client, email) => { try { const response = await client.get( `/People?$filter=Email%20eq%20'${encodeURIComponent(email)}'&$select=Id` ); return response.data[0]?.Id; } catch (error) { console.error("Error in findPerson:", error); throw error; } }; /** * Updates the user's authentication details in the API. * * @param {import("axios").AxiosInstance} client - The Axios client instance. * @param {number} PersonId - The ID of the user to update. * @param {string} UserName - The Auth0 ID to associate with the user. * @returns {Promise<void>} Resolves when the update is successful. */ const updateAuth = async (client, PersonId, UserName) => { try { const response = await client.post(`/UserLogins`, { EntityTypeId: 665, UserName, IsConfirmed: "true", PersonId, }); console.log("Auth update response:", response.data); } catch (error) { console.error("Error in updateAuth:", error); throw error; } }; /** * Handler that will be called during the execution of a PostUserRegistration flow. * * @param {Event} event - Details about the context and user that has registered. * @param {PostUserRegistrationAPI} api - Methods and utilities to help change the behavior after a signup. * @returns {Promise<void>} Resolves when the process completes successfully. */ exports.onExecutePostUserRegistration = async (event, api) => { try { const client = createClient( event.secrets.ROCK_API_URL, event.secrets.ROCK_API_TOKEN ); const email = event.user.email; if (email == null) { console.log( `User registration post-processing could not find email for ${event.user.user_id}.` ); return; } const rockPersonId = await findRockPersonId(client, email); if (rockPersonId == null) { console.log( `User registration post-processing could not find rockPersonId for ${event.user}.` ); return; } const rockUserName = `AUTH0_email|${event.user.user_id}`; await updateAuth(client, rockPersonId, rockUserName); console.log("User registration post-processing completed successfully."); } catch (error) { console.error("Error in post-user-registration handler:", error); } };