@cobuildlab/auth0-utils
Version:
This is package to deal with common scenarios working with auth0 platform
553 lines (547 loc) • 27.2 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAuth0Client = void 0;
var nanoid_1 = require("nanoid");
var node_fetch_1 = require("node-fetch");
var utils_1 = require("./utils");
var Auth0Client = /** @class */ (function () {
function Auth0Client(params) {
this.accessToken = null;
this.domain = params.domain;
this.clientId = params.clientId;
this.clienSecret = params.clienSecret;
}
Auth0Client.prototype.setupAccesToken = function () {
return __awaiter(this, void 0, void 0, function () {
var response, authResponse, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (this.accessToken) {
return [2 /*return*/];
}
_a.label = 1;
case 1:
_a.trys.push([1, 4, , 5]);
return [4 /*yield*/, (0, node_fetch_1.default)("https://".concat(this.domain, "/oauth/token"), {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
audience: "https://".concat(this.domain, "/api/v2/"),
grant_type: 'client_credentials',
client_id: this.clientId,
client_secret: this.clienSecret,
}),
})];
case 2:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 3:
authResponse = (_a.sent());
if (!authResponse.access_token) {
console.log('accessTokenError', authResponse);
throw new Error('There was a problem with the access token');
}
this.accessToken = authResponse.access_token;
return [3 /*break*/, 5];
case 4:
error_1 = _a.sent();
console.log(error_1);
return [3 /*break*/, 5];
case 5: return [2 /*return*/];
}
});
});
};
/**.
* This function creates a user in the auth0 database if the users already exits it fetch it and return it.
* this method need the following scopes from the M2M acces token "create:users" & "read:users"
*
* @param email - User email.
* @param connection - Database connection on Auth0.
* @param options - options
* @param options.sendVerificationEmail - if should send a verification email.
* @returns User.
*/
Auth0Client.prototype.createOrReturnUser = function (email, connection, options) {
return __awaiter(this, void 0, void 0, function () {
var user, error_2, user;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 2, , 5]);
return [4 /*yield*/, this.createAuth0User(email, connection, options)];
case 1:
user = _a.sent();
return [2 /*return*/, user];
case 2:
error_2 = _a.sent();
if (!JSON.stringify(error_2).includes('The user already exists')) return [3 /*break*/, 4];
return [4 /*yield*/, this.getUserByEmail(email)];
case 3:
user = _a.sent();
return [2 /*return*/, user];
case 4: throw error_2;
case 5: return [2 /*return*/];
}
});
});
};
/**.
*
* This function send a verification email to the .
* This method need the following scopes from the M2M acces token "update:users".
*
* If you want to change the "redirect to url" please check this doc.
* https://auth0.com/docs/brand-and-customize/email/customize-email-templates#configuring-the-redirect-to-url
*
* @param userId - The ID of the user.
* @returns Response of the email sent.
*/
Auth0Client.prototype.sendAuth0EmailVerification = function (userId) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_a.sent();
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/jobs/verification-email"), {
method: 'POST',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
body: JSON.stringify({
user_id: userId,
client_id: this.clientId,
}),
}))];
case 2: return [2 /*return*/, _a.sent()];
}
});
});
};
/**.
* This function creates a user in the auth0 database.
* this method need the following scopes from the M2M acces token "create:users"
*
* @param email - User email.
* @param connection - Database connection on Auth0.
* @param options - options
* @param options.sendVerificationEmail - if should send a verification email.
* @returns User.
*/
Auth0Client.prototype.createAuth0User = function (email, connection, options) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var password, userResponse;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_b.sent();
password = (0, nanoid_1.nanoid)(10);
if (!this.accessToken) {
throw new Error('No valid access token');
}
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/users"), {
method: 'POST',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
body: JSON.stringify({
email: email,
password: "*".concat(password, "*"),
connection: connection,
verify_email: (_a = options === null || options === void 0 ? void 0 : options.sendVerificationEmail) !== null && _a !== void 0 ? _a : false,
}),
}))];
case 2:
userResponse = _b.sent();
return [2 /*return*/, userResponse];
}
});
});
};
/**.
* This function creates a user in the auth0 database.
* This method need the following scopes from the M2M acces token "create:users"
*
* @param params - Params
* @param params.email - User email.
* @param params.password - USer Password.
* @param params.connection - Database connection on Auth0.
* @param params.options - Params options.
* @param params.options.sendVerificationEmail - if should send a verification email.
* @returns User.
*/
Auth0Client.prototype.createAuth0UserWithEmailAndPassword = function (params) {
var _a, _b;
return __awaiter(this, void 0, void 0, function () {
var userResponse;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_c.sent();
if (!this.accessToken) {
throw new Error('No valid access token');
}
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/users"), {
method: 'POST',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
body: JSON.stringify({
email: params.email,
password: params.password,
connection: params.connection,
verify_email: (_b = (_a = params.options) === null || _a === void 0 ? void 0 : _a.sendVerificationEmail) !== null && _b !== void 0 ? _b : false,
}),
}))];
case 2:
userResponse = _c.sent();
return [2 /*return*/, userResponse];
}
});
});
};
/**.
* This method returs a link for the user to reset the password.
* this method need the following scopes from the M2M acces token "create:user_tickets"
* @param params - User email.
* @param params.connectionId - the connectio id of the database. example: "con_131231231321"
* ID of the connection. If provided, allows the user to be specified using email instead of user_id. If you set this value, you must also send the email parameter. You cannot send user_id when specifying a connection_id.
* @param params.resultUrl - Url to redirect the user after the the user chage their password. example "https://myapp.com/callback/"
* @param params.email - the user email
* @param params.ttlSec - Number of seconds for which the ticket is valid before expiration. If unspecified or set to 0, this value defaults to 432000 seconds (5 days).
* @param params.clientId - ID of the client. If provided for tenants using New Universal Login experience, the user will be prompted to redirect to the default login route of the corresponding application once the ticket is used. See Configuring Default Login Routes for more details.
Conflicts with: result_url
* @param params.userId - user_id of for whom the ticket should be created.
Conflicts with: connection_id, email
* @returns User.
*/
Auth0Client.prototype.getResetPasswordLink = function (params) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var request, tikectResponse;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_b.sent();
if (!this.accessToken) {
throw new Error('No valid access token');
}
request = {
user_id: params.userId,
result_url: params.resultUrl,
client_id: params.clientId,
connection_id: params.connectionId,
email: params.email,
ttl_sec: (_a = params.ttlSec) !== null && _a !== void 0 ? _a : 0,
mark_email_as_verified: true,
};
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/tickets/password-change"), {
method: 'POST',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
body: JSON.stringify(request),
}))];
case 2:
tikectResponse = _b.sent();
return [2 /*return*/, tikectResponse];
}
});
});
};
/**.
* GET /api/v2/users
* this method need the following scopes from the M2M acces token "read:users, read:user_idp_tokens"
- Specify a search criteria for users
- Sort the users to be returned
- Select the fields to be returned
- Specify the number of users to retrieve per page and the page index.
The q query parameter can be used to get users that match the specified criteria using query string syntax.
Learn more about searching for users.
See https://auth0.com/docs/users/user-search/user-search-query-syntax
*
* @param params - Params.
* @param params.page - Page of the records.
* @param params.perPage - Size of the response.
* @param params.query - Query string to filter the users.
* @returns A list of users.
*/
Auth0Client.prototype.getUserList = function (params) {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, page, _c, perPage, query, urlAppend, fullUrl, usersResponse;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_a = params || {}, _b = _a.page, page = _b === void 0 ? 1 : _b, _c = _a.perPage, perPage = _c === void 0 ? 10 : _c, query = _a.query;
return [4 /*yield*/, this.setupAccesToken()];
case 1:
_d.sent();
urlAppend = query
? "page=".concat(page, "&per_page=").concat(perPage, "&q=").concat(query)
: "page=".concat(page, "&per_page=").concat(perPage);
fullUrl = "https://".concat(this.domain, "/api/v2/users?").concat(urlAppend);
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)(fullUrl, {
method: 'GET',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
}))];
case 2:
usersResponse = _d.sent();
return [2 /*return*/, usersResponse];
}
});
});
};
/**.
*DELETE /api/v2/users/{id}
Delete a user.
* This method need the following scopes from the M2M acces token "delete:users"
*
* @param id - Id of the user.
* @returns Success response.
*/
Auth0Client.prototype.deleteUser = function (id) {
return __awaiter(this, void 0, void 0, function () {
var usersResponse;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_a.sent();
return [4 /*yield*/, (0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/users/").concat(id), {
method: 'DELETE',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
})];
case 2:
usersResponse = _a.sent();
if (!(usersResponse.status >= 200 && usersResponse.status <= 299)) {
throw new Error('Fail to delete user');
}
return [2 /*return*/, usersResponse];
}
});
});
};
/**.
* GET /api/v2/users-by-email
Get user by its email.
* This method need the following scopes from the M2M acces token "read:users"
*
* @param email - Email of the user.
* @returns {Auth0User} The user.
*/
Auth0Client.prototype.getUserByEmail = function (email) {
return __awaiter(this, void 0, void 0, function () {
var searchUser, user;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_a.sent();
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/users-by-email?").concat(new URLSearchParams({
email: email,
}).toString()), {
method: 'GET',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
}))];
case 2:
searchUser = _a.sent();
user = searchUser[0];
return [2 /*return*/, user];
}
});
});
};
/**.
*PATCH /api/v2/users/USER_ID
Change password a user.
* This method need the following scopes from the M2M acces token "read:users", "update:users" & "update:users_app_metadata"
*
* @param email - Email of the user.
* @param password - New password.
* @returns {Auth0User} The id of the user to be blocked.
*/
Auth0Client.prototype.changePassword = function (email, password) {
return __awaiter(this, void 0, void 0, function () {
var searchUser, user_id, usersResponse;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_a.sent();
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/users-by-email?").concat(new URLSearchParams({
email: email,
}).toString()), {
method: 'GET',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
}))];
case 2:
searchUser = _a.sent();
user_id = searchUser[0].user_id;
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/users/").concat(user_id), {
method: 'PATCH',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
body: JSON.stringify({
password: password,
}),
}))];
case 3:
usersResponse = _a.sent();
return [2 /*return*/, usersResponse];
}
});
});
};
/**.
* Check user password.
*
* This method requires that the m2m application have "password" as a valid grant.
*
* @param email - Email of the user.
* @param password - New password.
* @returns {boolean} Boolean If are valid password.
*/
Auth0Client.prototype.validateUserCredentials = function (email, password) {
return __awaiter(this, void 0, void 0, function () {
var authenticateUserInput, response, data;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_a.sent();
authenticateUserInput = {
grant_type: 'password',
password: password,
client_id: this.clientId,
client_secret: this.clienSecret,
username: email,
audience: "https://".concat(this.domain, "/api/v2/"),
scope: 'profile email',
};
return [4 /*yield*/, (0, node_fetch_1.default)("https://".concat(this.domain, "/oauth/token"), {
method: 'post',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(authenticateUserInput),
})];
case 2:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 3:
data = _a.sent();
if (!response.ok && response.status !== 403) {
throw data;
}
else if (response.status === 403) {
return [2 /*return*/, false];
}
else {
return [2 /*return*/, true];
}
return [2 /*return*/];
}
});
});
};
/**.
* @param id - Email of the user.
* @param info - New info.
* @returns {Auth0User} User Update Response.
*/
Auth0Client.prototype.updateUserData = function (id, info) {
return __awaiter(this, void 0, void 0, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.setupAccesToken()];
case 1:
_a.sent();
return [4 /*yield*/, (0, utils_1.hanldeFetch)((0, node_fetch_1.default)("https://".concat(this.domain, "/api/v2/users/").concat(id), {
method: 'PATCH',
headers: {
'content-type': 'application/json',
Authorization: 'Bearer ' + this.accessToken,
},
body: JSON.stringify(info),
}))];
case 2:
response = _a.sent();
return [2 /*return*/, response];
}
});
});
};
return Auth0Client;
}());
/**
* @param params - Params tu create the client.
* @param params.domain - Auth0 tenant domain..
* @param params.clientId - Auth0 app client id.
* @param params.clienSecret - Auth0 app client secret.
* @returns Client with methods to interacts with Auth0.
*/
function createAuth0Client(params) {
return new Auth0Client(params);
}
exports.createAuth0Client = createAuth0Client;