@jacebenson/jsn 4.3.7-dev.13 → 4.3.7-dev.14

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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/package.json +1 -1
  3. package/src/auth.js +14 -12
package/README.md CHANGED
@@ -167,6 +167,8 @@ export SERVICENOW_OAUTH_TOKEN="***"
167
167
  jsn incidents list
168
168
  ```
169
169
 
170
+ For the credential identity, auth-method, diagnostics, migration, and concurrency contract, see [`docs/AUTH_LIFECYCLE.md`](docs/AUTH_LIFECYCLE.md).
171
+
170
172
  ## Local data
171
173
 
172
174
  JSN stores durable local data under `~/.jsn/`. Documentation lives in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jacebenson/jsn",
3
- "version": "4.3.7-dev.13",
3
+ "version": "4.3.7-dev.14",
4
4
  "description": "A command-line interface for ServiceNow that follows the Unix philosophy: simple, composable, and scriptable.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/auth.js CHANGED
@@ -41,30 +41,32 @@ function credKey(instance, username) {
41
41
 
42
42
  // ─── PKCE state persistence (shared with Go version) ───
43
43
 
44
- function pkceStatePath(instance) {
44
+ function pkceStatePath(instance, username) {
45
45
  const dir = path.join(globalConfigDir(), 'pkce');
46
46
  fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
47
- const filename = sanitizeKeyPart(instance) + '.json';
47
+ // A known profile identity gets its own pending-login slot. Keep the bare
48
+ // instance slot for legacy/no-profile flows, where no identity exists yet.
49
+ const filename = credKey(instance, username) + '.json';
48
50
  return path.join(dir, filename);
49
51
  }
50
52
 
51
- function savePKCEState(instance, pkce) {
52
- const filePath = pkceStatePath(instance);
53
+ function savePKCEState(instance, pkce, username) {
54
+ const filePath = pkceStatePath(instance, username);
53
55
  fs.writeFileSync(filePath, JSON.stringify(pkce, null, 2), { mode: 0o600 });
54
56
  }
55
57
 
56
- function loadPKCEState(instance) {
58
+ function loadPKCEState(instance, username) {
57
59
  try {
58
- const data = fs.readFileSync(pkceStatePath(instance), 'utf-8');
60
+ const data = fs.readFileSync(pkceStatePath(instance, username), 'utf-8');
59
61
  return JSON.parse(data);
60
62
  } catch {
61
63
  return null;
62
64
  }
63
65
  }
64
66
 
65
- function removePKCEState(instance) {
67
+ function removePKCEState(instance, username) {
66
68
  try {
67
- fs.unlinkSync(pkceStatePath(instance));
69
+ fs.unlinkSync(pkceStatePath(instance, username));
68
70
  } catch {
69
71
  // ignore
70
72
  }
@@ -746,7 +748,7 @@ export class AuthManager {
746
748
  instanceURL = normalizeInstanceURL(instanceURL);
747
749
  const clientID = getOAuthClientID();
748
750
  const pkce = generatePKCE();
749
- savePKCEState(instanceURL, pkce);
751
+ savePKCEState(instanceURL, pkce, username);
750
752
  const url = buildAuthURL(instanceURL, clientID, pkce);
751
753
  if (waitFile) {
752
754
  console.log(url);
@@ -766,7 +768,7 @@ export class AuthManager {
766
768
  const code = fs.readFileSync(filePath, 'utf-8').trim();
767
769
  if (code) {
768
770
  console.log(`\nAuthorization code found in ${filePath}`);
769
- removePKCEState(instanceURL);
771
+ removePKCEState(instanceURL, username);
770
772
  const newCreds = await this.exchangeCode(instanceURL, clientID, code, pkce);
771
773
  this.saveCredentials(instanceURL, newCreds, username || newCreds.username);
772
774
  console.log('Token exchange successful!\n');
@@ -838,7 +840,7 @@ export class AuthManager {
838
840
  async loginWithCode(instanceURL, code, username = this._activeUsername()) {
839
841
  instanceURL = normalizeInstanceURL(instanceURL);
840
842
  const clientID = getOAuthClientID();
841
- const pkce = loadPKCEState(instanceURL);
843
+ const pkce = loadPKCEState(instanceURL, username);
842
844
  if (!pkce) {
843
845
  throw errAuth(
844
846
  `No pending login session for ${instanceURL}.\n\n` +
@@ -848,7 +850,7 @@ export class AuthManager {
848
850
  ` jsn auth login ${instanceURL} --code CODE`
849
851
  );
850
852
  }
851
- removePKCEState(instanceURL);
853
+ removePKCEState(instanceURL, username);
852
854
 
853
855
  const newCreds = await this.exchangeCode(instanceURL, clientID, code, pkce);
854
856
  this.saveCredentials(instanceURL, newCreds, username || newCreds.username);