UNPKG

@simulacrum/auth0-simulator

Version:

Run local instance of Auth0 API for local development and integration testing

188 lines 8.56 kB
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