supertokens-node
Version:
NodeJS driver for SuperTokens core
96 lines (95 loc) • 4.58 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = getAPIInterface;
const utils_1 = require("../../multitenancy/utils");
const configUtils_1 = require("../../thirdparty/providers/configUtils");
const constants_1 = require("../constants");
function getAPIInterface(stInstance) {
return {
loginMethodsGET: async function ({ tenantId, clientType, options, userContext }) {
const tenantConfigRes = await options.recipeImplementation.getTenant({
tenantId,
userContext,
});
if (tenantConfigRes === undefined) {
throw new Error("Tenant not found");
}
const providerInputsFromStatic = options.staticThirdPartyProviders;
const providerConfigsFromCore = tenantConfigRes.thirdParty.providers;
const mergedProviders = (0, configUtils_1.mergeProvidersFromCoreAndStatic)(
providerConfigsFromCore,
providerInputsFromStatic,
tenantId === constants_1.DEFAULT_TENANT_ID
);
const finalProviderList = [];
for (const providerInput of mergedProviders) {
try {
const providerInstance = await (0, configUtils_1.findAndCreateProviderInstance)(
tenantId,
mergedProviders,
providerInput.config.thirdPartyId,
clientType,
userContext
);
if (providerInstance === undefined) {
throw new Error("should never come here"); // because creating instance from the merged provider list itself
}
finalProviderList.push({
id: providerInstance.id,
name: providerInstance.config.name,
});
} catch (err) {
if (err.type === "CLIENT_TYPE_NOT_FOUND_ERROR") {
continue;
}
throw err;
}
}
let firstFactors;
if (tenantConfigRes.firstFactors !== undefined) {
firstFactors = tenantConfigRes.firstFactors; // highest priority, config from core
} else if (options.staticFirstFactors !== undefined) {
firstFactors = options.staticFirstFactors; // next priority, static config
} else {
// Fallback to all available factors (de-duplicated)
firstFactors = Array.from(new Set(options.allAvailableFirstFactors));
}
// we now filter out all available first factors by checking if they are valid because
// we want to return the ones that can work. this would be based on what recipes are enabled
// on the core and also firstFactors configured in the core and supertokens.init
// Also, this way, in the front end, the developer can just check for firstFactors for
// enabled recipes in all cases irrespective of whether they are using MFA or not
let validFirstFactors = [];
for (const factorId of firstFactors) {
let validRes = await (0, utils_1.isValidFirstFactor)(stInstance, tenantId, factorId, userContext);
if (validRes.status === "OK") {
validFirstFactors.push(factorId);
}
if (validRes.status === "TENANT_NOT_FOUND_ERROR") {
throw new Error("Tenant not found");
}
}
return {
status: "OK",
emailPassword: {
enabled: validFirstFactors.includes("emailpassword"),
},
thirdParty: {
enabled: validFirstFactors.includes("thirdparty"),
providers: finalProviderList,
},
webauthn: {
enabled: validFirstFactors.includes("webauthn"),
},
passwordless: {
enabled:
validFirstFactors.includes("otp-email") ||
validFirstFactors.includes("otp-phone") ||
validFirstFactors.includes("link-email") ||
validFirstFactors.includes("link-phone"),
},
firstFactors: validFirstFactors,
};
},
};
}