-
Notifications
You must be signed in to change notification settings - Fork 22
feat(auth0): switch from cosmiconfig to configliere (#362) #363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
|
|
||
|
|
@@ -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 | ||
| 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Quick Start protocol example is inconsistent with the surrounding HTTPS guidance. Line 48 says the default startup URL is Also applies to: 48-48, 56-57 🤖 Prompt for AI Agents |
||
|
|
||
| ### Using Default User | ||
|
|
||
|
|
@@ -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/" | ||
| } | ||
| ``` | ||
|
|
@@ -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 | ||
|
|
||
|
|
||
| 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the configured protocol in the startup URL (and normalize IPv6 host formatting). Line 58 hardcodes 💡 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| `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; | ||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Startup message should not hardcode HTTPS in the example output. Line 20 always prints 💡 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| `password: 12345\n`, | ||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capitalize “GitHub” in user-facing docs.
Line 31 should use
GitHub issuefor 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
Source: Linters/SAST tools