@simulacrum/auth0-simulator
Version:
Run local instance of Auth0 API for local development and integration testing
188 lines • 8.56 kB
JavaScript
import { createLoginRedirectHandler } from "./login-redirect";
import { createWebMessageHandler } from "./web-message";
import { loginView } from "../views/login";
import { createTokens } from "./oauth-handlers";
import { assert } from "assert-ts";
import { stringify } from "querystring";
import { encode } from "base64-url";
import { userNamePasswordForm } from "../views/username-password";
import { decode as decodeToken } from "jsonwebtoken";
import { createPersonQuery } from "./utils";
const createLogger = (debug) => ({
log: (...args) => {
if (!debug) {
return;
}
console.dir(...args);
},
});
export const createAuth0Handlers = (simulationStore, serviceURL, options, debug) => {
let { audience, scope, clientID, rulesDirectory } = options;
let personQuery = createPersonQuery(simulationStore);
let authorizeHandlers = {
query: createLoginRedirectHandler(options),
web_message: createWebMessageHandler(),
};
let logger = createLogger(debug);
return {
["/heartbeat"]: function (_, res) {
res.status(200).json({ ok: true });
},
["/authorize"]: function (req, res, next) {
var _a;
logger.log({
"/authorize": {
body: req.body,
query: req.query,
session: req.session,
},
});
let currentUser = req.query.currentUser;
assert(!!req.session, "no session");
if (currentUser) {
// the request is a silent login.
// We fake an existing login by
// adding the user to the session
req.session.username = currentUser;
}
let responseMode = ((_a = req.query.response_mode) !== null && _a !== void 0 ? _a : "query");
assert(["query", "web_message"].includes(responseMode), `unknown response_mode ${responseMode}`);
let handler = authorizeHandlers[responseMode];
handler(req, res, next);
},
["/login"]: function (req, res) {
var _a, _b;
logger.log({ "/login": { body: req.body, query: req.query } });
let query = req.query;
let responseClientId = (_a = query.client_id) !== null && _a !== void 0 ? _a : clientID;
let responseAudience = (_b = query.audience) !== null && _b !== void 0 ? _b : audience;
assert(!!responseClientId, `no clientID assigned`);
let html = loginView({
domain: new URL(serviceURL(req)).host,
scope,
redirectUri: query.redirect_uri,
clientID: responseClientId,
audience: responseAudience,
loginFailed: false,
});
res.set("Content-Type", "text/html");
res.status(200).send(Buffer.from(html));
},
["/usernamepassword/login"]: function (req, res) {
var _a, _b;
logger.log({
"/usernamepassword/login": { body: req.body, query: req.query },
});
let { username, nonce, password } = req.body;
assert(!!username, "no username in /usernamepassword/login");
assert(!!nonce, "no nonce in /usernamepassword/login");
assert(!!req.session, "no session");
let user = personQuery((person) => {
var _a;
return ((_a = person.email) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === username.toLowerCase() &&
person.password === password;
});
if (!user) {
let query = req.query;
let responseClientId = (_a = query.client_id) !== null && _a !== void 0 ? _a : clientID;
let responseAudience = (_b = query.audience) !== null && _b !== void 0 ? _b : audience;
assert(!!clientID, `no clientID assigned`);
let html = loginView({
domain: new URL(serviceURL(req)).host,
scope,
redirectUri: query.redirect_uri,
clientID: responseClientId,
audience: responseAudience,
loginFailed: true,
});
res.set("Content-Type", "text/html");
res.status(400).send(html);
return;
}
req.session.username = username;
simulationStore.store.dispatch(simulationStore.actions.batchUpdater([
simulationStore.schema.sessions.patch({
[nonce]: { username, nonce },
}),
]));
res.status(200).send(userNamePasswordForm(req.body));
},
["/login/callback"]: function (req, res) {
let wctx = JSON.parse(req.body.wctx);
logger.log({
"/login/callback": { body: req.body, query: req.query, wctx },
});
let { redirect_uri, nonce } = wctx;
const session = simulationStore.schema.sessions.selectById(simulationStore.store.getState(), { id: nonce });
const { username } = session !== null && session !== void 0 ? session : {};
let encodedNonce = encode(`${nonce}:${username}`);
let qs = stringify({ code: encodedNonce, ...wctx });
let routerUrl = `${redirect_uri}?${qs}`;
res.status(302).redirect(routerUrl);
},
["/oauth/token"]: async function (req, res, next) {
var _a, _b, _c, _d;
logger.log({ "/oauth/token": { body: req.body, query: req.query } });
try {
let iss = serviceURL(req);
let responseClientId = (_b = (_a = req === null || req === void 0 ? void 0 : req.body) === null || _a === void 0 ? void 0 : _a.client_id) !== null && _b !== void 0 ? _b : clientID;
let responseAudience = (_d = (_c = req === null || req === void 0 ? void 0 : req.body) === null || _c === void 0 ? void 0 : _c.audience) !== null && _d !== void 0 ? _d : audience;
assert(!!responseClientId, "500::no clientID in options or request body");
let tokens = await createTokens({
simulationStore,
body: req.body,
iss,
clientID: responseClientId,
audience: responseAudience,
rulesDirectory,
scope,
});
res.status(200).json({
...tokens,
expires_in: 86400,
token_type: "Bearer",
});
}
catch (error) {
next(error);
}
},
["/v2/logout"]: function (req, res) {
var _a;
req.session = null;
let returnToUrl = (_a = req.query.returnTo) !== null && _a !== void 0 ? _a : req.headers.referer;
assert(typeof returnToUrl === "string", `no logical returnTo url`);
res.redirect(returnToUrl);
},
["/userinfo"]: function (req, res) {
var _a, _b;
let token = null;
if (req.headers.authorization) {
let authorizationHeader = req.headers.authorization;
token = (_a = authorizationHeader === null || authorizationHeader === void 0 ? void 0 : authorizationHeader.split(" ")) === null || _a === void 0 ? void 0 : _a[1];
}
else {
token = (_b = req === null || req === void 0 ? void 0 : req.query) === null || _b === void 0 ? void 0 : _b.access_token;
}
assert(!!token, "no authorization header or access_token");
let { sub } = decodeToken(token, { json: true });
let user = personQuery((person) => {
assert(!!person.id, `no email defined on person scenario`);
return person.id === sub;
});
assert(!!user, "no user in /userinfo");
let userinfo = {
sub,
name: user.name,
given_name: user.name,
family_name: user.name,
email: user.email,
email_verified: true,
locale: "en",
hd: "okta.com",
};
res.status(200).json(userinfo);
},
};
};
//# sourceMappingURL=auth0-handlers.js.map