@simulacrum/auth0-simulator
Version:
Run local instance of Auth0 API for local development and integration testing
144 lines (142 loc) • 3.94 kB
JavaScript
import "../store/entities.mjs";
import "../store/index.mjs";
import { createPersonQuery, deriveScope } from "./utils.mjs";
import { epochTime, expiresAt } from "../auth/date.mjs";
import { createJsonWebToken } from "../auth/jwt.mjs";
import { createRulesRunner } from "../rules/rules-runner.mjs";
import { createRefreshToken, issueRefreshToken } from "../auth/refresh-token.mjs";
import { assert } from "assert-ts";
import { decode } from "base64-url";
//#region src/handlers/oauth-handlers.ts
const createTokens = async ({ body, iss, clientID, audience, rulesDirectory, scope: scopeConfig, simulationStore }) => {
let { grant_type } = body;
let scope = deriveScope({
scopeConfig,
clientID,
audience
});
let accessToken = getBaseAccessToken({
iss,
grant_type,
scope,
audience
});
let user;
let nonce;
if (grant_type === "client_credentials") return { access_token: createJsonWebToken(accessToken) };
else if (grant_type === "refresh_token") {
let { refresh_token: refreshTokenValue } = body;
let refreshToken = JSON.parse(decode(refreshTokenValue));
user = createPersonQuery(simulationStore)((person) => person.id === refreshToken.user.id);
nonce = refreshToken.nonce;
assert(!!nonce, `400::No nonce in request`);
} else {
let result = verifyUserExistsInStore({
simulationStore,
body,
grant_type
});
user = result.user;
nonce = result.nonce;
}
assert(!!user, "500::No user found");
let { idTokenData, userData } = getIdToken({
body,
iss,
user,
clientID,
nonce
});
let context = {
clientID,
accessToken: {
scope,
sub: idTokenData.sub
},
idToken: idTokenData
};
await createRulesRunner(rulesDirectory)(userData, context);
return {
access_token: createJsonWebToken({
...accessToken,
...context.accessToken,
...scope.split(" ").includes("email") ? { email: user.email } : {}
}),
id_token: createJsonWebToken({
...userData,
...context.idToken
}),
refresh_token: issueRefreshToken(scope, grant_type) ? createRefreshToken({
exp: idTokenData.exp,
rotations: 0,
scope,
user,
nonce
}) : void 0
};
};
const getIdToken = ({ body, iss, user, clientID, nonce }) => {
let userData = {
name: body?.name ?? user.name,
email: body?.email ?? user.email,
email_verified: true,
user_id: body?.id ?? user.id,
nickname: body?.nickname,
picture: body?.picture ?? user.picture,
identities: body?.identities
};
assert(!!user.email, "500::User in store requires an email");
let idTokenData = {
alg: "RS256",
typ: "JWT",
iss,
exp: expiresAt(),
iat: epochTime(),
email: user.email,
aud: clientID,
sub: user.id
};
if (typeof nonce !== "undefined") idTokenData.nonce = nonce;
return {
userData,
idTokenData
};
};
const getBaseAccessToken = ({ iss, grant_type, scope, audience }) => ({
iss,
exp: expiresAt(),
iat: epochTime(),
aud: audience,
gty: grant_type,
scope
});
const verifyUserExistsInStore = ({ simulationStore, body, grant_type }) => {
let { code } = body;
let personQuery = createPersonQuery(simulationStore);
let nonce;
let username;
let password;
if (grant_type === "http://auth0.com/oauth/grant-type/passwordless/otp") username = body.username;
else if (grant_type === "password") {
username = body.username;
password = body.password;
} else {
assert(typeof code !== "undefined", "400::no code in /oauth/token");
[nonce, username] = decode(code).split(":");
assert(!!username, `400::no nonce in store for ${code}`);
}
let user = personQuery((person) => {
assert(!!person.email, `500::no email defined on person scenario`);
let valid = person.email.toLowerCase() === username.toLowerCase();
if (typeof password === "undefined") return valid;
else return valid && password === person.password;
});
assert(!!user, "401::Unauthorized");
return {
user,
nonce
};
};
//#endregion
export { createTokens };
//# sourceMappingURL=oauth-handlers.mjs.map