"code": "async function vouchedVerification(user, context, callback) {\n if (!configuration.VOUCHED_API_KEY || !configuration.VOUCHED_PUBLIC_KEY) {\n console.log('Missing required configuration. Skipping.');\n return callback(null, user, context);\n }\n\n /* ----------- START helpers ----------- */\n const axios = require('axios');\n const url = require('url');\n const { Auth0RedirectRuleUtilities } = require('@auth0/rule-utilities@0.1.0');\n\n const ruleUtils = new Auth0RedirectRuleUtilities(\n user,\n context,\n configuration\n );\n\n const defaultApiUrl = 'https://verify.vouched.id/api';\n const defaultUiUrl = 'https://i.vouched.id';\n const idTokenClaim = 'https://vouched.id/is_verified';\n\n const getJobByToken = async (apiKey, jobToken, apiUrl) => {\n return getJob(apiKey, { token: jobToken }, apiUrl);\n };\n\n const getJobById = async (apiKey, jobId, apiUrl) => {\n return getJob(apiKey, { id: jobId }, apiUrl);\n };\n\n const getJob = async (apiKey, params, apiUrl) => {\n const response = await axios({\n headers: {\n 'X-Api-Key': apiKey,\n 'Content-Type': 'application/json'\n },\n baseURL: apiUrl,\n url: '/jobs',\n params: params\n });\n const items = response.data.items;\n if (items.length === 0) {\n throw new Error(\n `Unable to find Job with the following params: ${JSON.stringify(\n params\n )}`\n );\n }\n return items[0];\n };\n\n const createPacket = async (\n apiKey,\n publicKey,\n continueUrl,\n user,\n apiUrl = defaultApiUrl\n ) => {\n const requestBody = {\n pk: publicKey,\n uid: user.user_id,\n continueUrl\n };\n\n if (user.given_name) requestBody.firstName = user.given_name;\n\n if (user.family_name) requestBody.lastName = user.family_name;\n\n const response = await axios({\n method: 'post',\n headers: {\n 'X-Api-Key': apiKey,\n 'Content-Type': 'application/json'\n },\n baseURL: apiUrl,\n url: '/packet/auth0',\n data: requestBody\n });\n const data = response.data;\n if (data.errors) {\n throw new Error(`${data.errors[0].message}`);\n }\n return data.id;\n };\n\n const isJobForUser = (job, userId) => {\n try {\n return (\n job.request.properties.filter(\n (prop) => prop.name === 'uid' && prop.value === userId\n ).length === 1\n );\n } catch (e) {\n return false;\n }\n };\n\n const extractResults = (job) => {\n const { id, status, reviewSuccess, result } = job;\n return {\n id,\n status,\n reviewSuccess,\n result\n };\n };\n\n const isJobVerified = (job) => {\n try {\n return job.result.success || job.reviewSuccess;\n } catch (e) {\n return false;\n }\n };\n\n const redirectToVerification = (packetId, baseUrl = defaultUiUrl) => {\n const redirectUrl = new url.URL(`${baseUrl}/auth0`);\n redirectUrl.searchParams.append('id', packetId);\n return redirectUrl.href;\n };\n\n /* ----------- END helpers ----------- */\n\n user.app_metadata = user.app_metadata || {};\n const vouchedApiUrl = configuration.VOUCHED_API_URL || defaultApiUrl;\n\n try {\n const jobToken = ruleUtils.queryParams.jobToken;\n if (ruleUtils.isRedirectCallback && jobToken) {\n // get job from API\n const job = await getJobByToken(\n configuration.VOUCHED_API_KEY,\n jobToken,\n vouchedApiUrl\n );\n\n // check if job's user is the same as current user\n if (!isJobForUser(job, user.user_id)) {\n return callback(\n new Error(`The ID Verification results do not belong to this user.`)\n );\n }\n\n // update app metadata w/ results\n user.app_metadata.vouched = extractResults(job);\n await auth0.users.updateAppMetadata(user.user_id, user.app_metadata);\n }\n\n const vouchedResults = user.app_metadata.vouched;\n if (vouchedResults) {\n if (!isJobVerified(vouchedResults)) {\n // user failed id verification\n const mostRecentJob = await getJobById(\n configuration.VOUCHED_API_KEY,\n vouchedResults.id,\n vouchedApiUrl\n );\n\n // check if job's user is the same as current user\n if (!isJobForUser(mostRecentJob, user.user_id)) {\n return callback(\n new Error(`The ID Verification results do not belong to this user.`)\n );\n }\n\n // user is now verified, update app metadata\n if (isJobVerified(mostRecentJob)) {\n user.app_metadata.vouched = extractResults(mostRecentJob);\n await auth0.users.updateAppMetadata(user.user_id, user.app_metadata);\n } else {\n // user failed verification check and doesn't have an override\n if (configuration.VOUCHED_ID_TOKEN_CLAIM === 'true') {\n context.idToken[idTokenClaim] = false;\n }\n if (configuration.VOUCHED_VERIFICATION_OPTIONAL === 'true') {\n return callback(null, user, context);\n }\n\n return callback(new Error(`This user's ID cannot be verified.`));\n }\n }\n } else {\n // create Auth0 packet to securely pass info to Vouched\n const packetId = await createPacket(\n configuration.VOUCHED_API_KEY,\n configuration.VOUCHED_PUBLIC_KEY,\n `https://${context.request.hostname}/continue`,\n user\n );\n\n // user doesn't have a verification result, redirect to Vouched with packet\n if (ruleUtils.canRedirect) {\n context.redirect = { url: redirectToVerification(packetId) };\n }\n return callback(null, user, context);\n }\n } catch (e) {\n return callback(e);\n }\n\n if (configuration.VOUCHED_ID_TOKEN_CLAIM === 'true') {\n context.idToken[idTokenClaim] = true;\n }\n\n return callback(null, user, context);\n}"
0 commit comments