@simulacrum/auth0-simulator
Version:
Run local instance of Auth0 API for local development and integration testing
136 lines • 4.98 kB
JavaScript
import { assert } from "assert-ts";
import { decode, decode as decodeBase64 } from "base64-url";
import { epochTime, expiresAt } from "../auth/date";
import { createJsonWebToken } from "../auth/jwt";
import { createRulesRunner } from "../rules/rules-runner";
import { deriveScope, createPersonQuery } from "./utils";
import { createRefreshToken, issueRefreshToken } from "../auth/refresh-token";
export 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) };
}
// TODO: check refresh_token expiry date
else if (grant_type === "refresh_token") {
let { refresh_token: refreshTokenValue } = body;
let refreshToken = JSON.parse(decode(refreshTokenValue));
let findUser = createPersonQuery(simulationStore);
user = findUser((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,
};
let rulesRunner = createRulesRunner(rulesDirectory);
// the rules mutate the values
await rulesRunner(userData, context);
return {
access_token: createJsonWebToken({
...accessToken,
...context.accessToken,
}),
id_token: createJsonWebToken({
...userData,
...context.idToken,
}),
refresh_token: issueRefreshToken(scope, grant_type)
? createRefreshToken({
exp: idTokenData.exp,
rotations: 0,
scope,
user,
nonce,
})
: undefined,
};
};
export const getIdToken = ({ body, iss, user, clientID, nonce, }) => {
var _a, _b, _c, _d;
let userData = {
name: (_a = body === null || body === void 0 ? void 0 : body.name) !== null && _a !== void 0 ? _a : user.name,
email: (_b = body === null || body === void 0 ? void 0 : body.email) !== null && _b !== void 0 ? _b : user.email,
email_verified: true,
user_id: (_c = body === null || body === void 0 ? void 0 : body.id) !== null && _c !== void 0 ? _c : user.id,
nickname: body === null || body === void 0 ? void 0 : body.nickname,
picture: (_d = body === null || body === void 0 ? void 0 : body.picture) !== null && _d !== void 0 ? _d : user.picture,
identities: body === null || body === void 0 ? void 0 : 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 };
};
export 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 === "password") {
username = body.username;
password = body.password;
}
else {
// specifically grant_type === 'authorization_code'
// but naively using it to handle other cases at the moment
assert(typeof code !== "undefined", "400::no code in /oauth/token");
[nonce, username] = decodeBase64(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 };
};
//# sourceMappingURL=oauth-handlers.js.map