Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 108 additions & 16 deletions packages/auth0/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Auth0 simulator

Read about this simulator on our blog: [Simplified Local Development and Testing with Auth0 Simulation](https://frontside.com/blog/2022-01-13-auth0-simulator/).
Read about this simulator on our blog: [Simplified Local Development and Testing with Auth0
Simulation](https://frontside.com/blog/2022-01-13-auth0-simulator/).

## Table of Contents

Expand All @@ -11,22 +12,33 @@ Read about this simulator on our blog: [Simplified Local Development and Testing
- [Code](#code)
- [Example](#example)
- [Configuration](#configuration)
- [CLI Flags](#cli-flags)
- [JSON Config Files](#json-config-files)
- [Environment Variables](#environment-variables)
- [Programmatic Options](#programmatic-options)
- [Options](#options)
- [Rules](#rules)
- [Endpoints](#endpoints)

Please read the [main README](../../README.md) for more background on simulacrum.

The auth0 simulator has been initially written to mimic the responses of a real auth0 server that is called from auth0 client libraries like [auth0/react](https://auth0.com/docs/quickstart/spa/react/01-login) and [auth0-spa-js](https://github.com/auth0/auth0-spa-js) that use the OpenID [authorization code flow](https://developer.okta.com/docs/concepts/oauth-openid/).
The auth0 simulator has been initially written to mimic the responses of a real auth0 server that is
called from auth0 client libraries like
[auth0/react](https://auth0.com/docs/quickstart/spa/react/01-login) and
[auth0-spa-js](https://github.com/auth0/auth0-spa-js) that use the OpenID [authorization code
flow](https://developer.okta.com/docs/concepts/oauth-openid/).

If this does not meet your needs then please create a github issue to start a conversation about adding new OpenID flows.
If this does not meet your needs then please create a github issue to start a conversation about

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Capitalize “GitHub” in user-facing docs.

Line 31 should use GitHub issue for correct product naming.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~31-~31: The official name of this software platform is spelled with a capital “H”.
Context: ...ot meet your needs then please create a github issue to start a conversation about add...

(GITHUB)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/auth0/README.md` at line 31, The README.md file at line 31 contains
an instance of "github issue" that should be capitalized as "GitHub issue" to
follow proper product naming conventions. Locate the text "please create a
github issue to start a conversation about" and capitalize the "g" in "github"
to "GitHub" to match the official product name.

Source: Linters/SAST tools

adding new OpenID flows.

## Quick Start

This quick start assumes you have your own app with Auth0.

> [!IMPORTANT]
> The Auth0 clients expect the server to be served as `https`, and will throw an error if it is served as `http`. Currently, we rely on a certificate available in the home directory. On first run, you will see instructions on how to set up this certificate through `mkcert`.
> [!IMPORTANT]
> The Auth0 clients expect the server to be served as `https`, and will throw an error if it is
> served as `http`. Currently, we rely on a certificate available in the home directory. On first
> run, you will see instructions on how to set up this certificate through `mkcert`.
Comment on lines +39 to +41

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Quick Start protocol example is inconsistent with the surrounding HTTPS guidance.

Line 48 says the default startup URL is http://localhost:4400, while Lines 39-41 and the default config sample (Lines 56-57) point to HTTPS. Please align these to a single default behavior to avoid setup confusion.

Also applies to: 48-48, 56-57

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/auth0/README.md` around lines 39 - 41, The README documentation
contains an inconsistency between the HTTPS requirement stated in lines 39-41
and the Quick Start protocol example on line 48. Update the default startup URL
example on line 48 from using HTTP to HTTPS protocol (change
http://localhost:4400 to https://localhost:4400) to align with both the Auth0
client HTTPS requirement documented in lines 39-41 and the default config sample
shown in lines 56-57, ensuring consistent messaging throughout the
documentation.


### Using Default User

Expand All @@ -36,12 +48,13 @@ You may start a server directly from the command line.
npx @simulacrum/auth0-simulator # this will start a simulation server at http://localhost:4400
```

Given no further input, it will use the default values as below. This will point your app at the simulation instead of the Auth0 endpoint.
Given no further input, it will use the default values as below. This will point your app at the
simulation instead of the Auth0 endpoint.

```json
{
"domain": "https://localhost:4400",
"clientId": "00000000000000000000000000000000",
"clientID": "00000000000000000000000000000000",
"audience": "https://thefrontside.auth0.com/api/v1/"
}
```
Expand All @@ -63,29 +76,108 @@ By passing an `initialState`, you may control the initial users in the store.

### Example

The folks at Auth0 maintain many samples such as [github.com/auth0-samples/auth0-react-samples](https://github.com/auth0-samples/auth0-react-samples). Follow the instructions to run the sample, set the configuration in `auth_config.json` to match the defaults as noted above, and run the Auth0 simulation server with `npx auth0-simulator`.
The folks at Auth0 maintain many samples such as
[github.com/auth0-samples/auth0-react-samples](https://github.com/auth0-samples/auth0-react-samples).
Follow the instructions to run the sample, set the configuration in `auth_config.json` to match the
defaults as noted above, and run the Auth0 simulation server with `npx auth0-simulator`.

## Configuration

The Auth0 Simulator uses [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig) to load the configuration options. This provides many options in where to place your configuration. Using the module name, `auth0Simulator`, you could, for example, set your configuration in a `.auth0Simulatorrc.json` file.
The Auth0 Simulator uses [configliere](https://github.com/thefrontside/configliere) to parse
configuration from CLI flags, environment variables, JSON config files, and programmatic options.

### Options
### CLI Flags

When running from the command line, you can pass configuration as flags:

```bash
npx @simulacrum/auth0-simulator --port 5000 --audience https://myapp.com/api
```

The CLI also accepts an explicit `start` command, though it remains the default:

```bash
npx @simulacrum/auth0-simulator start --port 5000
```

Run with `--help` to see all available flags:

```bash
npx @simulacrum/auth0-simulator --help
```

### JSON Config Files

The `options` field supports the [auth0 configuration fields](https://auth0.com/docs/quickstart/spa/vanillajs#configure-auth0). The option fields should match the fields in the client application that is calling the auth0 server.
You can stage configuration through a JSON file with `-c` and then override values with CLI flags:

The `scope` also accepts an array of objects containing `clientId`, `scope` and optionally `audience` to enable dynamic scopes from a single simulator. This should allow multiple clients to all use the same simulator. Additionally, setting the `clientId: "default"` will enable a default fallback scope so every client does not need to be included.
```bash
npx @simulacrum/auth0-simulator -c auth0-simulator.json --port 5000
```

Values from CLI flags still take precedence over environment variables and config file values.

### Environment Variables

Configuration can also be set via environment variables. Field names are mapped to
`UPPER_SNAKE_CASE`:

```bash
PORT=5000 AUDIENCE=https://myapp.com/api npx @simulacrum/auth0-simulator
```

### Programmatic Options

When using the simulator as a library, pass options directly:

```js
import { simulation } from "@simulacrum/auth0-simulator";

const app = simulation({
options: {
port: 5000,
audience: "https://myapp.com/api",
},
});
```

### Options

An optional [`rulesDirectory` field](#rules) can specify a directory of [auth0 rules](https://auth0.com/docs/rules) code files, more on this [below](#rules).
The `options` field supports the [auth0 configuration
fields](https://auth0.com/docs/quickstart/spa/vanillajs#configure-auth0). The option fields should
match the fields in the client application that is calling the auth0 server.

| Option | CLI Flag | Env Var | Description |
| ---------------- | ------------------- | ----------------- | -------------------------------- |
| `port` | `--port`, `-p` | `PORT` | Port to listen on |
| `domain` | `--domain` | `DOMAIN` | Server domain |
| `audience` | `--audience` | `AUDIENCE` | Auth0 audience |
| `clientID` | `--client-id` | `CLIENT_ID` | Auth0 client ID |
| `scope` | `--scope` | `SCOPE` | Auth0 scope |
| `clientSecret` | `--client-secret` | `CLIENT_SECRET` | Client secret |
| `rulesDirectory` | `--rules-directory` | `RULES_DIRECTORY` | Directory containing auth0 rules |
| `connection` | `--connection` | `CONNECTION` | Auth0 connection |
| `protocol` | `--protocol` | `PROTOCOL` | Server protocol (https/http) |

The `scope` also accepts an array of objects containing `clientID`, `scope` and optionally
`audience` to enable dynamic scopes from a single simulator (programmatic usage only). This should
allow multiple clients to all use the same simulator. Additionally, setting the `clientID:
"default"` will enable a default fallback scope so every client does not need to be included.

An optional [`rulesDirectory` field](#rules) can specify a directory of [auth0
rules](https://auth0.com/docs/rules) code files, more on this [below](#rules).

### Rules

It is possible to run [auth0 rules](https://auth0.com/docs/rules) if the compiled code files are on disk and all located in the same directory.
It is possible to run [auth0 rules](https://auth0.com/docs/rules) if the compiled code files are on
disk and all located in the same directory.

Set the `rulesDirectory` of the [options field](#options) to a path relative to your current working directory.
Set the `rulesDirectory` of the [options field](#options) to a path relative to your current working
directory.

For example, a [sample rules directory](./test/rules) is in the auth0 package for testing.

If we want to run these rules files then we would add the `rulesDirectory` field to the [options object](#options).
If we want to run these rules files then we would add the `rulesDirectory` field to the [options
object](#options).

## Endpoints

Expand Down
85 changes: 73 additions & 12 deletions packages/auth0/bin/start.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,74 @@
#!/usr/bin/env node
import { simulation, defaultUser } from "../dist/index.mjs";

const app = simulation();
app.listen(4400, () =>
console.log(
`Auth0 simulation server started at https://localhost:4400\n` +
`Visit the root route to view all available routes.\n\n` +
`Point your configuration at this simulation server and use the default user below.\n` +
`Email: ${defaultUser.email}\nPassword: ${defaultUser.password}\n` +
`\nPress Ctrl+C to stop the server`,
),
);
import { createContext } from "configliere";
import { auth0Program, readJsonConfig, simulation, defaultUser } from "@simulacrum/auth0-simulator";

const args = process.argv.slice(2);
const envs = [{ name: "env", value: /** @type {Record<string, string>} */ (process.env) }];

async function main() {
let parser = auth0Program.parse({ args, envs });

if (!parser.ok) {
throw parser.error;
}

if (parser.value.help) {
console.log(auth0Program.help({ args }));
return;
}

if (parser.value.version) {
console.log(parser.value.version);
return;
}

const command = parser.value.config;

if (command.help) {
console.log(command.text);
return;
}

switch (command.name) {
case "start": {
let configPath = command.config.config;
let values = configPath ? [{ name: configPath, value: readJsonConfig(configPath) }] : [];
let configParser = command.config.next(values[0]?.value ?? {});
let input = {
args: parser.remainder.args ?? [],
envs: parser.remainder.envs ?? envs,
values,
};
let result = configParser.parse(input, createContext(input));

if (!result.ok) {
throw result.error;
}

const app = simulation({ config: result.value });

/** @param {{ server: any; port: any }} listening */
const { server, port } = await app.listen();
const info = server.address();
const host =
typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
? info.address
: "localhost";
console.log(
`Auth0 simulation server started at https://${host}:${port}\n` +
`Visit the root route to view all available routes.\n\n` +
Comment on lines +53 to +59

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the configured protocol in the startup URL (and normalize IPv6 host formatting).

Line 58 hardcodes https://, so --protocol http still prints an HTTPS URL. Also, IPv6 addresses like ::1 should be bracketed before composing a URL.

💡 Proposed fix
-      const host =
-        typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
-          ? info.address
-          : "localhost";
+      const protocol = result.value.protocol ?? "https";
+      const rawHost =
+        typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
+          ? info.address
+          : "localhost";
+      const host = rawHost.includes(":") ? `[${rawHost}]` : rawHost;
       console.log(
-        `Auth0 simulation server started at https://${host}:${port}\n` +
+        `Auth0 simulation server started at ${protocol}://${host}:${port}\n` +
           `Visit the root route to view all available routes.\n\n` +
           `Point your configuration at this simulation server and use the default user below.\n` +
           `Email: ${defaultUser.email}\nPassword: ${defaultUser.password}\n` +
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const host =
typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
? info.address
: "localhost";
console.log(
`Auth0 simulation server started at https://${host}:${port}\n` +
`Visit the root route to view all available routes.\n\n` +
const protocol = result.value.protocol ?? "https";
const rawHost =
typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
? info.address
: "localhost";
const host = rawHost.includes(":") ? `[${rawHost}]` : rawHost;
console.log(
`Auth0 simulation server started at ${protocol}://${host}:${port}\n` +
`Visit the root route to view all available routes.\n\n` +
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/auth0/bin/start.mjs` around lines 53 - 59, The startup URL
construction in the console.log statement hardcodes the protocol as https://
instead of using the configured protocol parameter, and does not handle IPv6
address formatting (which requires brackets around the address in URLs). Modify
the URL string construction to use the protocol variable that should be
available from the command-line arguments or configuration, and add logic to
check if the host is an IPv6 address (contains colons) and wrap it in brackets
before inserting it into the URL template.

`Point your configuration at this simulation server and use the default user below.\n` +
`Email: ${defaultUser.email}\nPassword: ${defaultUser.password}\n` +
`\nPress Ctrl+C to stop the server`,
);
return;
}
default:
throw new TypeError(`Unknown command ${command.name}`);
}
}

main().catch((error) => {
console.error(error instanceof Error ? error.message : String(error));
process.exitCode = 1;
});
16 changes: 12 additions & 4 deletions packages/auth0/example/index.mts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@ let app = simulation({
},
},
});
app.listen(undefined, () =>

app.listen().then(({ server, port }) => {
const info = server.address();
const host =
typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
? info.address
: "localhost";
console.log(
`auth0 simulation server started at https://localhost:4400\nusername: default@example.com\npassword: 12345\n`,
),
);
`Auth0 simulation server started at https://${host}:${port}\n` +
`username: default@example.com\n` +
Comment on lines +15 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Startup message should not hardcode HTTPS in the example output.

Line 20 always prints https://... even when the simulator is configured for HTTP, and raw IPv6 hosts should be bracketed for a valid URL string.

💡 Proposed fix
 app.listen().then(({ server, port }) => {
   const info = server.address();
-  const host =
+  const protocol = "https"; // or derive from configured protocol if exposed in this example
+  const rawHost =
     typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
       ? info.address
       : "localhost";
+  const host = rawHost.includes(":") ? `[${rawHost}]` : rawHost;
   console.log(
-    `Auth0 simulation server started at https://${host}:${port}\n` +
+    `Auth0 simulation server started at ${protocol}://${host}:${port}\n` +
       `username: default@example.com\n` +
       `password: 12345\n`,
   );
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const host =
typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
? info.address
: "localhost";
console.log(
`auth0 simulation server started at https://localhost:4400\nusername: default@example.com\npassword: 12345\n`,
),
);
`Auth0 simulation server started at https://${host}:${port}\n` +
`username: default@example.com\n` +
const protocol = "https"; // or derive from configured protocol if exposed in this example
const rawHost =
typeof info === "object" && info?.address && !["::", "0.0.0.0"].includes(info.address)
? info.address
: "localhost";
const host = rawHost.includes(":") ? `[${rawHost}]` : rawHost;
console.log(
`Auth0 simulation server started at ${protocol}://${host}:${port}\n` +
`username: default@example.com\n` +
`password: 12345\n`,
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/auth0/example/index.mts` around lines 15 - 21, The startup message
in the console.log statement hardcodes "https://" in the URL regardless of the
actual protocol configuration of the simulator, and IPv6 addresses like "::"
need to be wrapped in brackets to form valid URLs. Modify the console.log
message to use the correct protocol that matches the simulator's actual
configuration (likely HTTP for a local simulator) and ensure IPv6 addresses are
wrapped in brackets when constructing the URL string for host.

`password: 12345\n`,
);
});
2 changes: 1 addition & 1 deletion packages/auth0/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@
"@simulacrum/foundation-simulator": "^0.8.0",
"assert-ts": "^0.3.4",
"base64-url": "^2.3.3",
"configliere": "^0.4.0",
"cookie-session": "^2.1.0",
"cors": "^2.8.6",
"cosmiconfig": "^9.0.0",
"express": "^5.2.1",
"html-entities": "^2.5.2",
"jose": "^5.9.6",
Expand Down
Loading
Loading