@deque/axe-auth 1.1.0-next.816dc5a1 → 1.1.0-next.8e9934f2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -17
- package/credits.json +42 -0
- package/dist/cli/commonArgs.d.ts +53 -37
- package/dist/cli/commonArgs.help.d.ts +1 -1
- package/dist/cli/commonArgs.help.js +12 -11
- package/dist/cli/commonArgs.js +37 -66
- package/dist/cli/errors.d.ts +0 -10
- package/dist/cli/errors.js +1 -16
- package/dist/cli/testUtils.js +3 -3
- package/dist/cli/types.d.ts +8 -11
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.help.d.ts +1 -1
- package/dist/commands/login.help.js +11 -5
- package/dist/commands/login.js +38 -14
- package/dist/commands/logout.d.ts +1 -1
- package/dist/commands/logout.help.d.ts +1 -1
- package/dist/commands/logout.help.js +5 -4
- package/dist/commands/logout.js +1 -15
- package/dist/commands/token.d.ts +2 -7
- package/dist/commands/token.help.d.ts +1 -1
- package/dist/commands/token.help.js +5 -5
- package/dist/commands/token.js +10 -22
- package/dist/index.js +23 -51
- package/dist/oauth/authorize.d.ts +7 -0
- package/dist/oauth/authorize.js +2 -1
- package/dist/oauth/discoverOIDC.js +26 -0
- package/dist/oauth/discoverSSOConfig.d.ts +47 -0
- package/dist/oauth/discoverSSOConfig.js +105 -0
- package/dist/oauth/getValidAccessToken.js +1 -0
- package/dist/oauth/tokenStore.d.ts +5 -0
- package/dist/oauth/tokenStore.js +5 -1
- package/docs/architecture.md +27 -18
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -32,21 +32,17 @@ Run `axe-auth <command> --help` for command-specific options.
|
|
|
32
32
|
|
|
33
33
|
### Common configuration
|
|
34
34
|
|
|
35
|
-
`axe-auth
|
|
35
|
+
`axe-auth` discovers its OAuth coordinates by calling `<server>/api/sso-config` on the axe server. Users only supply (or default to) the axe server URL — never the underlying Keycloak URL, realm, or client ID.
|
|
36
36
|
|
|
37
|
-
| Flag | Env var
|
|
38
|
-
| ---------------------------- |
|
|
39
|
-
| `--server` | `
|
|
40
|
-
| `--
|
|
41
|
-
| `--
|
|
42
|
-
| `--allow-insecure-issuer` | — | Permit non-loopback http issuers (default is https only; loopback http is always allowed). |
|
|
43
|
-
| `--no-allow-insecure-issuer` | — | Force `allowInsecureIssuer=false` for this call, overriding the stored value. Mutually exclusive with `--allow-insecure-issuer`. |
|
|
37
|
+
| Flag | Env var | Notes |
|
|
38
|
+
| ---------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
39
|
+
| `--server` | `AXE_SERVER_URL` | axe server URL. Defaults to `https://axe.deque.com` (SaaS prod) when neither flag nor env var is set, so SaaS users pass no flags at all. Customers on other deployments override with their own axe server URL. |
|
|
40
|
+
| `--allow-insecure-issuer` | — | Permit non-loopback http URLs (default is https only; loopback http is always allowed). Applies to `login` only; `token` and `logout` use the policy persisted at login. |
|
|
41
|
+
| `--no-allow-insecure-issuer` | — | Force `allowInsecureIssuer=false` for the new `login` (and the entry it persists). Mutually exclusive with `--allow-insecure-issuer`. `token` and `logout` ignore this flag. |
|
|
44
42
|
|
|
45
|
-
|
|
43
|
+
`axe-auth` stores one set of credentials per machine. On a successful `login`, the discovered issuer / client / insecure-issuer values are persisted alongside the tokens, so subsequent `axe-auth token` and `axe-auth logout` invocations work flag-free — a typical scripted call is just `$(axe-auth token)`.
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
There is no concurrent multi-issuer support. Logging in to a second Keycloak overwrites the previous tokens; an interactive prompt confirms the switch before destroying the existing session, and `--force` skips the prompt.
|
|
45
|
+
There is no concurrent multi-issuer support. Logging in to a second deployment overwrites the previous tokens; an interactive prompt confirms the switch before destroying the existing session, and `--force` skips the prompt.
|
|
50
46
|
|
|
51
47
|
### Exit codes
|
|
52
48
|
|
|
@@ -60,11 +56,11 @@ There is no concurrent multi-issuer support. Logging in to a second Keycloak ove
|
|
|
60
56
|
### Examples
|
|
61
57
|
|
|
62
58
|
```sh
|
|
63
|
-
# First-time login (opens your browser)
|
|
64
|
-
axe-auth login
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
# First-time login on Deque SaaS prod (opens your browser, no flags needed)
|
|
60
|
+
axe-auth login
|
|
61
|
+
|
|
62
|
+
# First-time login on a non-SaaS-prod deployment
|
|
63
|
+
axe-auth login --server https://axe.customer.dequecloud.com
|
|
68
64
|
|
|
69
65
|
# Pull a fresh access token for use in shell substitution
|
|
70
66
|
docker run -e AXE_ACCESS_TOKEN="$(axe-auth token)" axe-mcp-server
|
package/credits.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"@napi-rs/keyring@1.2.0": {
|
|
3
|
+
"name": "@napi-rs/keyring",
|
|
4
|
+
"version": "1.2.0",
|
|
5
|
+
"licenses": "MIT",
|
|
6
|
+
"path": "/home/runner/work/axe-mcp-server/axe-mcp-server/node_modules/.pnpm/@napi-rs+keyring@1.2.0/node_modules/@napi-rs/keyring",
|
|
7
|
+
"licenseText": "MIT License\n\nCopyright (c) 2020 N-API for Rust\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
|
|
8
|
+
"licenseFile": "/home/runner/work/axe-mcp-server/axe-mcp-server/node_modules/.pnpm/@napi-rs+keyring@1.2.0/node_modules/@napi-rs/keyring/LICENSE",
|
|
9
|
+
"copyright": "Copyright (c) 2020 N-API for Rust"
|
|
10
|
+
},
|
|
11
|
+
"@napi-rs/keyring-linux-x64-gnu@1.2.0": {
|
|
12
|
+
"name": "@napi-rs/keyring-linux-x64-gnu",
|
|
13
|
+
"version": "1.2.0",
|
|
14
|
+
"licenses": "MIT",
|
|
15
|
+
"path": "/home/runner/work/axe-mcp-server/axe-mcp-server/node_modules/.pnpm/@napi-rs+keyring-linux-x64-gnu@1.2.0/node_modules/@napi-rs/keyring-linux-x64-gnu",
|
|
16
|
+
"licenseText": "# `@napi-rs/keyring-linux-x64-gnu`\n\nThis is the **x86_64-unknown-linux-gnu** binary for `@napi-rs/keyring`\n",
|
|
17
|
+
"licenseFile": "/home/runner/work/axe-mcp-server/axe-mcp-server/node_modules/.pnpm/@napi-rs+keyring-linux-x64-gnu@1.2.0/node_modules/@napi-rs/keyring-linux-x64-gnu/README.md"
|
|
18
|
+
},
|
|
19
|
+
"remove-trailing-slash@0.1.1": {
|
|
20
|
+
"name": "remove-trailing-slash",
|
|
21
|
+
"version": "0.1.1",
|
|
22
|
+
"licenses": "MIT",
|
|
23
|
+
"path": "/home/runner/work/axe-mcp-server/axe-mcp-server/node_modules/.pnpm/remove-trailing-slash@0.1.1/node_modules/remove-trailing-slash",
|
|
24
|
+
"licenseText": "# remove-trailing-slash\n\nremoves trailing slashes\n\n## Installation\n\nwith [component(1)](http://component.io):\n\n $ component install stephenmathieson/remove-trailing-slash\n\nwith [npm](https://npmjs.org/):\n\n $ npm install remove-trailing-slash\n\n## API\n\n### `removeTrailingSlash(str)`\n\nRemoves trailing slashes from the given `str`\n\n## Example\n\n```js\nvar slashes = require('remove-trailing-slash')\n\nslashes('http://google.com/').should.be.equal('http://google.com');\n```\n\n## License\n\nMIT\n",
|
|
25
|
+
"licenseFile": "/home/runner/work/axe-mcp-server/axe-mcp-server/node_modules/.pnpm/remove-trailing-slash@0.1.1/node_modules/remove-trailing-slash/readme.md",
|
|
26
|
+
"repository": "https://github.com/stephenmathieson/remove-trailing-slash",
|
|
27
|
+
"publisher": "Stephen Mathieson",
|
|
28
|
+
"email": "me@stephenmathieson.com"
|
|
29
|
+
},
|
|
30
|
+
"ts-dedent@2.2.0": {
|
|
31
|
+
"name": "ts-dedent",
|
|
32
|
+
"version": "2.2.0",
|
|
33
|
+
"licenses": "MIT",
|
|
34
|
+
"path": "/home/runner/work/axe-mcp-server/axe-mcp-server/node_modules/.pnpm/ts-dedent@2.2.0/node_modules/ts-dedent",
|
|
35
|
+
"licenseText": "MIT License\n\nCopyright (c) 2018 Tamino Martinius\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n",
|
|
36
|
+
"licenseFile": "/home/runner/work/axe-mcp-server/axe-mcp-server/node_modules/.pnpm/ts-dedent@2.2.0/node_modules/ts-dedent/LICENSE",
|
|
37
|
+
"repository": "https://github.com/tamino-martinius/node-ts-dedent",
|
|
38
|
+
"publisher": "Tamino Martinius",
|
|
39
|
+
"email": "dev@zaku.eu",
|
|
40
|
+
"copyright": "Copyright (c) 2018 Tamino Martinius"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/dist/cli/commonArgs.d.ts
CHANGED
|
@@ -1,66 +1,82 @@
|
|
|
1
1
|
import type { ParseArgsConfig } from "node:util";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Default axe server URL for `axe-auth` users on Deque's SaaS prod
|
|
4
|
+
* deployment. The CLI's `--server` flag (and `AXE_SERVER_URL` env)
|
|
5
|
+
* override this; non-prod customers must supply their own walnut URL.
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
clientId: string;
|
|
10
|
-
allowInsecureIssuer: boolean;
|
|
11
|
-
}
|
|
12
|
-
/** Common configuration the three CLI verbs share. */
|
|
7
|
+
export declare const DEFAULT_WALNUT_URL = "https://axe.deque.com";
|
|
8
|
+
/** Common configuration the CLI verbs share. */
|
|
13
9
|
export interface CommonArgs {
|
|
14
|
-
/** OIDC issuer URL, built as `${server}/realms/${realm}`. */
|
|
15
|
-
issuerURL: string;
|
|
16
|
-
/** OAuth client ID. */
|
|
17
|
-
clientId: string;
|
|
18
10
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
11
|
+
* axe server URL (walnut). Used by `login` to fetch
|
|
12
|
+
* `/api/sso-config` and derive the OAuth issuer / realm / client
|
|
13
|
+
* coordinates. `token` and `logout` operate on the stored entry
|
|
14
|
+
* alone and ignore this value.
|
|
15
|
+
*/
|
|
16
|
+
walnutURL: string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether to permit non-loopback http walnut/issuer URLs. Loopback
|
|
19
|
+
* hosts (`localhost` / `127.0.0.1` / `[::1]`) are always allowed
|
|
20
|
+
* over http; this flag is the opt-in for non-loopback http
|
|
21
|
+
* deployments.
|
|
22
22
|
*/
|
|
23
23
|
allowInsecureIssuer: boolean;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* `parseArgs`-shaped options describing the flags every CLI verb
|
|
27
|
-
* accepts (server
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* accepts (--server, --allow-insecure-issuer, --no-allow-insecure-issuer).
|
|
28
|
+
* Subcommands spread this into their own `options` so they can add
|
|
29
|
+
* verb-specific flags alongside.
|
|
30
30
|
*
|
|
31
31
|
* Node's `parseArgs` doesn't support `--no-` boolean negation
|
|
32
32
|
* natively, so the opt-out is registered as its own flag. Passing
|
|
33
33
|
* both `--allow-insecure-issuer` and `--no-allow-insecure-issuer` is
|
|
34
|
-
* treated as user error and rejected
|
|
35
|
-
* is the only way to force `allowInsecureIssuer: false` for a single
|
|
36
|
-
* invocation when the stored entry has it set to `true`.
|
|
34
|
+
* treated as user error and rejected.
|
|
37
35
|
*/
|
|
38
36
|
export declare const COMMON_OPTIONS: NonNullable<ParseArgsConfig["options"]>;
|
|
39
37
|
/** Subset of `parseArgs(...).values` this helper consumes. */
|
|
40
38
|
export interface ParsedCommonValues {
|
|
41
39
|
server?: string;
|
|
42
|
-
realm?: string;
|
|
43
|
-
"client-id"?: string;
|
|
44
40
|
"allow-insecure-issuer"?: boolean;
|
|
45
41
|
"no-allow-insecure-issuer"?: boolean;
|
|
46
42
|
}
|
|
47
43
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* `
|
|
51
|
-
*
|
|
52
|
-
*
|
|
44
|
+
* Subset of a stored entry used as a fallback for
|
|
45
|
+
* `allowInsecureIssuer` when the user passes neither
|
|
46
|
+
* `--allow-insecure-issuer` nor `--no-allow-insecure-issuer`.
|
|
47
|
+
* Sourced from `KeyringTokenStore.load()` by the dispatcher.
|
|
48
|
+
*
|
|
49
|
+
* `walnutURL` is carried alongside so the fallback only applies when
|
|
50
|
+
* the user is targeting the same deployment as the stored entry —
|
|
51
|
+
* otherwise a dev-time HTTP-allow setting would silently carry over
|
|
52
|
+
* to a prod login.
|
|
53
|
+
*/
|
|
54
|
+
export interface StoredCommonDefaults {
|
|
55
|
+
walnutURL: string;
|
|
56
|
+
allowInsecureIssuer: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolves common configuration from parsed flag values, falling
|
|
60
|
+
* back to `AXE_SERVER_URL` when `--server` is absent and finally to
|
|
61
|
+
* the SaaS prod walnut URL when neither is set.
|
|
53
62
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
63
|
+
* `allowInsecureIssuer` is consumed by `login` (it is forwarded to
|
|
64
|
+
* SSO discovery and the OAuth flow). The fallback to a stored value
|
|
65
|
+
* exists so an interactive re-login on a private dev instance does
|
|
66
|
+
* not need the flag re-passed when the previous login set it. The
|
|
67
|
+
* fallback is gated on the resolved walnut URL matching the stored
|
|
68
|
+
* one: a user logging in to a different deployment must opt back in
|
|
69
|
+
* with `--allow-insecure-issuer` explicitly. The `token` and `logout`
|
|
70
|
+
* verbs do **not** consume this resolved value — they read
|
|
71
|
+
* `allowInsecureIssuer` directly from the keychain entry's metadata,
|
|
72
|
+
* so flag/env input is silently ignored there (and the help text for
|
|
73
|
+
* those verbs documents that).
|
|
59
74
|
*
|
|
60
75
|
* @param values The `values` object returned from `parseArgs`.
|
|
61
76
|
* @param env Environment to consult for fallback. Defaults to
|
|
62
77
|
* `process.env`; injected for test determinism.
|
|
63
|
-
* @param defaults Stored
|
|
64
|
-
*
|
|
78
|
+
* @param defaults Stored fallback for `allowInsecureIssuer` plus the
|
|
79
|
+
* `walnutURL` it was minted against. Pass `null` (or omit) when
|
|
80
|
+
* nothing is stored.
|
|
65
81
|
*/
|
|
66
|
-
export declare function parseCommonArgs(values: ParsedCommonValues, env?: NodeJS.ProcessEnv, defaults?:
|
|
82
|
+
export declare function parseCommonArgs(values: ParsedCommonValues, env?: NodeJS.ProcessEnv, defaults?: StoredCommonDefaults | null): CommonArgs;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Help-text fragment describing the flags every CLI verb shares. */
|
|
2
|
-
export declare const HELP_COMMON_OPTIONS = " --server <url>
|
|
2
|
+
export declare const HELP_COMMON_OPTIONS = " --server <url> axe server URL. Used by `login` to fetch\n /api/sso-config and derive the OAuth\n coordinates. Falls back to AXE_SERVER_URL,\n then to https://axe.deque.com (SaaS prod).\n --allow-insecure-issuer Permit non-loopback http URLs (default is\n https only; loopback http is always\n allowed). Applies to `login` only;\n `token` and `logout` use the policy\n persisted at login.\n --no-allow-insecure-issuer\n Force allowInsecureIssuer=false for the new\n `login` (and the entry it persists).\n Ignored by `token` and `logout`.\n Mutually exclusive with\n --allow-insecure-issuer.\n -h, --help Show this help.";
|
|
@@ -2,18 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.HELP_COMMON_OPTIONS = void 0;
|
|
4
4
|
/** Help-text fragment describing the flags every CLI verb shares. */
|
|
5
|
-
exports.HELP_COMMON_OPTIONS = ` --server <url>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
--
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
exports.HELP_COMMON_OPTIONS = ` --server <url> axe server URL. Used by \`login\` to fetch
|
|
6
|
+
/api/sso-config and derive the OAuth
|
|
7
|
+
coordinates. Falls back to AXE_SERVER_URL,
|
|
8
|
+
then to https://axe.deque.com (SaaS prod).
|
|
9
|
+
--allow-insecure-issuer Permit non-loopback http URLs (default is
|
|
10
|
+
https only; loopback http is always
|
|
11
|
+
allowed). Applies to \`login\` only;
|
|
12
|
+
\`token\` and \`logout\` use the policy
|
|
13
|
+
persisted at login.
|
|
14
14
|
--no-allow-insecure-issuer
|
|
15
|
-
Force allowInsecureIssuer=false for
|
|
16
|
-
|
|
15
|
+
Force allowInsecureIssuer=false for the new
|
|
16
|
+
\`login\` (and the entry it persists).
|
|
17
|
+
Ignored by \`token\` and \`logout\`.
|
|
17
18
|
Mutually exclusive with
|
|
18
19
|
--allow-insecure-issuer.
|
|
19
20
|
-h, --help Show this help.`;
|
package/dist/cli/commonArgs.js
CHANGED
|
@@ -3,94 +3,65 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.COMMON_OPTIONS = void 0;
|
|
6
|
+
exports.COMMON_OPTIONS = exports.DEFAULT_WALNUT_URL = void 0;
|
|
7
7
|
exports.parseCommonArgs = parseCommonArgs;
|
|
8
8
|
const remove_trailing_slash_1 = __importDefault(require("remove-trailing-slash"));
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Default axe server URL for `axe-auth` users on Deque's SaaS prod
|
|
11
|
+
* deployment. The CLI's `--server` flag (and `AXE_SERVER_URL` env)
|
|
12
|
+
* override this; non-prod customers must supply their own walnut URL.
|
|
13
|
+
*/
|
|
14
|
+
exports.DEFAULT_WALNUT_URL = "https://axe.deque.com";
|
|
11
15
|
/**
|
|
12
16
|
* `parseArgs`-shaped options describing the flags every CLI verb
|
|
13
|
-
* accepts (server
|
|
14
|
-
*
|
|
15
|
-
*
|
|
17
|
+
* accepts (--server, --allow-insecure-issuer, --no-allow-insecure-issuer).
|
|
18
|
+
* Subcommands spread this into their own `options` so they can add
|
|
19
|
+
* verb-specific flags alongside.
|
|
16
20
|
*
|
|
17
21
|
* Node's `parseArgs` doesn't support `--no-` boolean negation
|
|
18
22
|
* natively, so the opt-out is registered as its own flag. Passing
|
|
19
23
|
* both `--allow-insecure-issuer` and `--no-allow-insecure-issuer` is
|
|
20
|
-
* treated as user error and rejected
|
|
21
|
-
* is the only way to force `allowInsecureIssuer: false` for a single
|
|
22
|
-
* invocation when the stored entry has it set to `true`.
|
|
24
|
+
* treated as user error and rejected.
|
|
23
25
|
*/
|
|
24
26
|
exports.COMMON_OPTIONS = {
|
|
25
27
|
server: { type: "string" },
|
|
26
|
-
realm: { type: "string" },
|
|
27
|
-
"client-id": { type: "string" },
|
|
28
28
|
"allow-insecure-issuer": { type: "boolean" },
|
|
29
29
|
"no-allow-insecure-issuer": { type: "boolean" },
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
|
-
* Resolves
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* is absent, then to a `StoredConfig` from the keychain when none
|
|
36
|
-
* of those are set at all. Flag wins over env wins over stored.
|
|
32
|
+
* Resolves common configuration from parsed flag values, falling
|
|
33
|
+
* back to `AXE_SERVER_URL` when `--server` is absent and finally to
|
|
34
|
+
* the SaaS prod walnut URL when neither is set.
|
|
37
35
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
36
|
+
* `allowInsecureIssuer` is consumed by `login` (it is forwarded to
|
|
37
|
+
* SSO discovery and the OAuth flow). The fallback to a stored value
|
|
38
|
+
* exists so an interactive re-login on a private dev instance does
|
|
39
|
+
* not need the flag re-passed when the previous login set it. The
|
|
40
|
+
* fallback is gated on the resolved walnut URL matching the stored
|
|
41
|
+
* one: a user logging in to a different deployment must opt back in
|
|
42
|
+
* with `--allow-insecure-issuer` explicitly. The `token` and `logout`
|
|
43
|
+
* verbs do **not** consume this resolved value — they read
|
|
44
|
+
* `allowInsecureIssuer` directly from the keychain entry's metadata,
|
|
45
|
+
* so flag/env input is silently ignored there (and the help text for
|
|
46
|
+
* those verbs documents that).
|
|
43
47
|
*
|
|
44
48
|
* @param values The `values` object returned from `parseArgs`.
|
|
45
49
|
* @param env Environment to consult for fallback. Defaults to
|
|
46
50
|
* `process.env`; injected for test determinism.
|
|
47
|
-
* @param defaults Stored
|
|
48
|
-
*
|
|
51
|
+
* @param defaults Stored fallback for `allowInsecureIssuer` plus the
|
|
52
|
+
* `walnutURL` it was minted against. Pass `null` (or omit) when
|
|
53
|
+
* nothing is stored.
|
|
49
54
|
*/
|
|
50
55
|
function parseCommonArgs(values, env = process.env, defaults = null) {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// posture of the call without identifying a different issuer, so
|
|
61
|
-
// it should compose with the stored issuer/client fallback.
|
|
62
|
-
const noFlagOrEnv = !server && !realm && !clientId;
|
|
63
|
-
if (noFlagOrEnv && defaults) {
|
|
64
|
-
return {
|
|
65
|
-
issuerURL: defaults.issuerURL,
|
|
66
|
-
clientId: defaults.clientId,
|
|
67
|
-
allowInsecureIssuer,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const missing = [];
|
|
71
|
-
if (!server)
|
|
72
|
-
missing.push("--server (or AXE_OAUTH_SERVER)");
|
|
73
|
-
if (!realm)
|
|
74
|
-
missing.push("--realm (or AXE_OAUTH_REALM)");
|
|
75
|
-
if (!clientId)
|
|
76
|
-
missing.push("--client-id (or AXE_OAUTH_CLIENT_ID)");
|
|
77
|
-
if (missing.length > 0) {
|
|
78
|
-
throw new errors_1.MissingConfigError(missing);
|
|
79
|
-
}
|
|
80
|
-
// The `missing.length` check above already threw when any of these
|
|
81
|
-
// were absent. The `assert` calls narrow `server` / `realm` /
|
|
82
|
-
// `clientId` from `string | undefined` to `string` for the return
|
|
83
|
-
// expression, replacing the non-null `!` shortcut with a runtime
|
|
84
|
-
// check that gives a real error if the invariant is ever broken.
|
|
85
|
-
(0, strict_1.default)(server);
|
|
86
|
-
(0, strict_1.default)(realm);
|
|
87
|
-
(0, strict_1.default)(clientId);
|
|
88
|
-
const serverBase = (0, remove_trailing_slash_1.default)(server);
|
|
89
|
-
return {
|
|
90
|
-
issuerURL: `${serverBase}/realms/${realm}`,
|
|
91
|
-
clientId,
|
|
92
|
-
allowInsecureIssuer,
|
|
93
|
-
};
|
|
56
|
+
const walnutURL = (0, remove_trailing_slash_1.default)(values.server ?? env.AXE_SERVER_URL ?? exports.DEFAULT_WALNUT_URL);
|
|
57
|
+
// Only inherit the stored `allowInsecureIssuer` when the incoming
|
|
58
|
+
// walnut URL matches the stored one. A user logging in to a
|
|
59
|
+
// different deployment must opt back in via `--allow-insecure-issuer`
|
|
60
|
+
// explicitly; otherwise a dev-time HTTP-allow setting would silently
|
|
61
|
+
// carry over to a prod login.
|
|
62
|
+
const matchingDefaults = defaults && defaults.walnutURL === walnutURL ? defaults : null;
|
|
63
|
+
const allowInsecureIssuer = resolveAllowInsecureIssuer(values, matchingDefaults);
|
|
64
|
+
return { walnutURL, allowInsecureIssuer };
|
|
94
65
|
}
|
|
95
66
|
/**
|
|
96
67
|
* Resolves `allowInsecureIssuer` from the positive flag, its
|
package/dist/cli/errors.d.ts
CHANGED
|
@@ -12,16 +12,6 @@ export declare class CLIError extends Error {
|
|
|
12
12
|
readonly exitCode: number;
|
|
13
13
|
constructor(code: CLIErrorCode, message: string);
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Thrown by `parseCommonArgs` when one or more of `server`, `realm`,
|
|
17
|
-
* or `clientId` cannot be resolved from flags, env vars, or the
|
|
18
|
-
* keychain default. Carries `missing` so the dispatcher can pair the
|
|
19
|
-
* list with extra context (e.g. a keychain-load failure).
|
|
20
|
-
*/
|
|
21
|
-
export declare class MissingConfigError extends Error {
|
|
22
|
-
readonly missing: readonly string[];
|
|
23
|
-
constructor(missing: readonly string[]);
|
|
24
|
-
}
|
|
25
15
|
/**
|
|
26
16
|
* Returns the `message` of an `Error`-shaped value, or its `String`
|
|
27
17
|
* coercion otherwise. Used in user-facing error templates so
|
package/dist/cli/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.CLIError = void 0;
|
|
4
4
|
exports.describeError = describeError;
|
|
5
5
|
const EXIT_CODE_BY_ERROR_CODE = {
|
|
6
6
|
NOT_AUTHENTICATED: 1,
|
|
@@ -27,21 +27,6 @@ class CLIError extends Error {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
exports.CLIError = CLIError;
|
|
30
|
-
/**
|
|
31
|
-
* Thrown by `parseCommonArgs` when one or more of `server`, `realm`,
|
|
32
|
-
* or `clientId` cannot be resolved from flags, env vars, or the
|
|
33
|
-
* keychain default. Carries `missing` so the dispatcher can pair the
|
|
34
|
-
* list with extra context (e.g. a keychain-load failure).
|
|
35
|
-
*/
|
|
36
|
-
class MissingConfigError extends Error {
|
|
37
|
-
missing;
|
|
38
|
-
constructor(missing) {
|
|
39
|
-
super(`Missing required configuration: ${missing.join(", ")}.`);
|
|
40
|
-
this.name = "MissingConfigError";
|
|
41
|
-
this.missing = missing;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
exports.MissingConfigError = MissingConfigError;
|
|
45
30
|
/**
|
|
46
31
|
* Returns the `message` of an `Error`-shaped value, or its `String`
|
|
47
32
|
* coercion otherwise. Used in user-facing error templates so
|
package/dist/cli/testUtils.js
CHANGED
|
@@ -71,9 +71,10 @@ function makeStore(initial) {
|
|
|
71
71
|
function entry(tokens, overrides = {}) {
|
|
72
72
|
return {
|
|
73
73
|
tokens,
|
|
74
|
-
issuerURL: "https://auth.example.com/realms/prod",
|
|
74
|
+
issuerURL: "https://auth.example.com/auth/realms/prod",
|
|
75
75
|
clientId: "axe-auth",
|
|
76
76
|
allowInsecureIssuer: false,
|
|
77
|
+
walnutURL: "https://axe.example.com",
|
|
77
78
|
...overrides,
|
|
78
79
|
};
|
|
79
80
|
}
|
|
@@ -92,8 +93,7 @@ function captureDeps(overrides = {}) {
|
|
|
92
93
|
*/
|
|
93
94
|
function commonArgs(overrides = {}) {
|
|
94
95
|
return {
|
|
95
|
-
|
|
96
|
-
clientId: "axe-auth",
|
|
96
|
+
walnutURL: "https://axe.example.com",
|
|
97
97
|
allowInsecureIssuer: false,
|
|
98
98
|
...overrides,
|
|
99
99
|
};
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -55,21 +55,18 @@ export interface CommandSpec {
|
|
|
55
55
|
readonly helpText: string;
|
|
56
56
|
/**
|
|
57
57
|
* Verb-specific `parseArgs` options. Common options
|
|
58
|
-
* (`--server` / `--
|
|
58
|
+
* (`--server` / `--allow-insecure-issuer` / `--no-allow-insecure-issuer`)
|
|
59
59
|
* are added by the dispatcher; do not duplicate them here.
|
|
60
60
|
*/
|
|
61
61
|
readonly options: VerbOptions;
|
|
62
62
|
/**
|
|
63
|
-
* `true` if this verb cannot run without
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* the dispatcher passes a sentinel-empty `CommonArgs` to `run()`
|
|
71
|
-
* instead of erroring, so the verb's own empty/corrupt-entry
|
|
72
|
-
* branch fires.
|
|
63
|
+
* `true` if this verb cannot run without a usable walnut URL
|
|
64
|
+
* (login). `false` for verbs that operate on the stored entry
|
|
65
|
+
* alone (token, logout) and have their own "not authenticated" /
|
|
66
|
+
* "already logged out" handling for the empty-entry case. With
|
|
67
|
+
* the SaaS prod default in `parseCommonArgs`, the walnut URL is
|
|
68
|
+
* never strictly missing, but this flag remains for future
|
|
69
|
+
* required-config additions.
|
|
73
70
|
*/
|
|
74
71
|
readonly requiresConfig: boolean;
|
|
75
72
|
/**
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { authorize } from "../oauth/authorize";
|
|
2
|
+
import { discoverSSOConfig } from "../oauth/discoverSSOConfig";
|
|
2
3
|
import { type TokenStore } from "../oauth/tokenStore";
|
|
3
4
|
import type { CommonArgs } from "../cli/commonArgs";
|
|
4
5
|
import type { CommandDeps } from "../cli/types";
|
|
@@ -8,6 +9,8 @@ export interface LoginDeps extends CommandDeps {
|
|
|
8
9
|
isInteractive?: boolean;
|
|
9
10
|
/** Override `authorize` (for tests). */
|
|
10
11
|
authorize?: typeof authorize;
|
|
12
|
+
/** Override the SSO discovery helper (for tests). */
|
|
13
|
+
discoverSSOConfig?: typeof discoverSSOConfig;
|
|
11
14
|
/**
|
|
12
15
|
* Override the token store. Defaults to a fresh
|
|
13
16
|
* `KeyringTokenStore()`. The same instance is passed to `authorize`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Help text for `axe-auth login --help`. */
|
|
2
|
-
export declare const HELP_LOGIN = "axe-auth login\n\nOpen a browser, complete the OAuth 2.0 Authorization Code + PKCE\nflow against
|
|
2
|
+
export declare const HELP_LOGIN = "axe-auth login\n\nOpen a browser, complete the OAuth 2.0 Authorization Code + PKCE\nflow against the customer's Keycloak realm, and persist the\nresulting tokens to the OS keychain.\n\nThe CLI discovers the OAuth coordinates by calling\n`<server>/api/sso-config` on the axe server, so users only need to\nsupply (or default to) the axe server URL \u2014 never the underlying\nKeycloak URL, realm, or client ID directly.\n\nUsage:\n axe-auth login [--server <url>] [--force]\n\n With no flags, the SaaS prod axe server URL (https://axe.deque.com)\n is used. Customers on other deployments pass --server (or set\n AXE_SERVER_URL).\n\nOptions:\n --server <url> axe server URL. Used by `login` to fetch\n /api/sso-config and derive the OAuth\n coordinates. Falls back to AXE_SERVER_URL,\n then to https://axe.deque.com (SaaS prod).\n --allow-insecure-issuer Permit non-loopback http URLs (default is\n https only; loopback http is always\n allowed). Applies to `login` only;\n `token` and `logout` use the policy\n persisted at login.\n --no-allow-insecure-issuer\n Force allowInsecureIssuer=false for the new\n `login` (and the entry it persists).\n Ignored by `token` and `logout`.\n Mutually exclusive with\n --allow-insecure-issuer.\n -h, --help Show this help.\n --force Re-authenticate without prompting even if\n a valid token is already stored.\n\nBehavior when already authenticated:\n axe-auth stores one entry per machine. If a valid entry already\n exists, an interactive session prompts for confirmation before\n overwriting it \u2014 even when the new login targets a different\n issuer or client (logging in to B destroys A's tokens). Pass\n --force to skip the prompt. In a non-interactive session (no TTY)\n --force is required; otherwise the command refuses to overwrite\n stored tokens and exits non-zero.\n\nExit codes:\n 0 Success; tokens persisted to the keychain.\n 2 Configuration error or flow failure.\n 3 Login cancelled at the prompt.";
|
|
@@ -6,14 +6,20 @@ const commonArgs_help_1 = require("../cli/commonArgs.help");
|
|
|
6
6
|
exports.HELP_LOGIN = `axe-auth login
|
|
7
7
|
|
|
8
8
|
Open a browser, complete the OAuth 2.0 Authorization Code + PKCE
|
|
9
|
-
flow against
|
|
10
|
-
to the OS keychain.
|
|
9
|
+
flow against the customer's Keycloak realm, and persist the
|
|
10
|
+
resulting tokens to the OS keychain.
|
|
11
|
+
|
|
12
|
+
The CLI discovers the OAuth coordinates by calling
|
|
13
|
+
\`<server>/api/sso-config\` on the axe server, so users only need to
|
|
14
|
+
supply (or default to) the axe server URL — never the underlying
|
|
15
|
+
Keycloak URL, realm, or client ID directly.
|
|
11
16
|
|
|
12
17
|
Usage:
|
|
13
|
-
axe-auth login --server <url>
|
|
18
|
+
axe-auth login [--server <url>] [--force]
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
With no flags, the SaaS prod axe server URL (https://axe.deque.com)
|
|
21
|
+
is used. Customers on other deployments pass --server (or set
|
|
22
|
+
AXE_SERVER_URL).
|
|
17
23
|
|
|
18
24
|
Options:
|
|
19
25
|
${commonArgs_help_1.HELP_COMMON_OPTIONS}
|