@baseworks/auth 0.2.3 → 0.2.5

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/dist/cli.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { Command } from 'commander';
2
+
3
+ interface AuthCliDeps {
4
+ /** Origin of the auth mount, e.g. `http://127.0.0.1:3003` (no `/v1/auth`). */
5
+ authBase: string | (() => string);
6
+ cliName?: string;
7
+ /** Persist the identity token (app decides where). */
8
+ onToken: (token: string) => void | Promise<void>;
9
+ /** Clear persisted credentials/context. */
10
+ onLogout?: () => void | Promise<void>;
11
+ /** Open the browser automatically (default true). */
12
+ openBrowser?: boolean;
13
+ }
14
+ declare function addAuthCommands(program: Command, deps: AuthCliDeps): void;
15
+
16
+ export { type AuthCliDeps, addAuthCommands };
package/dist/cli.js ADDED
@@ -0,0 +1,62 @@
1
+ import {
2
+ pollCliAuth,
3
+ startCliAuth
4
+ } from "./chunk-C4V5LCFA.js";
5
+
6
+ // src/cli.ts
7
+ import { spawn } from "child_process";
8
+ import { Command } from "commander";
9
+ import { clr, kv, success, warn, fatal } from "@baseworks/cli/display";
10
+ function resolveBase(b) {
11
+ return (typeof b === "function" ? b() : b).replace(/\/+$/, "");
12
+ }
13
+ function openInBrowser(url) {
14
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
15
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
16
+ try {
17
+ spawn(cmd, args, { stdio: "ignore", detached: true }).unref();
18
+ } catch {
19
+ }
20
+ }
21
+ function jwtSub(token) {
22
+ try {
23
+ const seg = token.split(".")[1];
24
+ if (!seg) return void 0;
25
+ const json = Buffer.from(seg.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8");
26
+ return JSON.parse(json).sub;
27
+ } catch {
28
+ return void 0;
29
+ }
30
+ }
31
+ function addAuthCommands(program, deps) {
32
+ const cli = deps.cliName ?? "cli";
33
+ program.addCommand(
34
+ new Command("login").description("Log in via browser (OIDC/PKCE)").option("--no-open", "Do not open the browser automatically").action(async (opts) => {
35
+ const base = resolveBase(deps.authBase);
36
+ const start = await startCliAuth(base).catch((e) => fatal(`Could not reach auth service at ${base}: ${e.message}`));
37
+ console.log(`
38
+ ${clr.dim}Opening your browser to sign in\u2026${clr.reset}`);
39
+ console.log(` ${clr.dim}If it does not open, visit:${clr.reset}
40
+ ${clr.cyan}${start.url}${clr.reset}
41
+ `);
42
+ if (deps.openBrowser !== false && opts.open !== false) openInBrowser(start.url);
43
+ const { token } = await pollCliAuth(base, start.state).catch((e) => fatal(e.message));
44
+ await deps.onToken(token);
45
+ const sub = jwtSub(token);
46
+ success("Logged in.");
47
+ if (sub) kv([["user id", sub]]);
48
+ console.log(` ${clr.dim}Next: ${cli} use \xB7 ${cli} orgs${clr.reset}
49
+ `);
50
+ })
51
+ );
52
+ program.addCommand(
53
+ new Command("logout").description("Clear saved credentials and active context").action(async () => {
54
+ if (deps.onLogout) await deps.onLogout();
55
+ else warn("No logout handler configured.");
56
+ success("Logged out.");
57
+ })
58
+ );
59
+ }
60
+ export {
61
+ addAuthCommands
62
+ };
package/dist/edge.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  getSessionFromCookies
3
- } from "./chunk-5W4TEXCT.js";
4
- import {
5
- parseJwtPayload
6
- } from "./chunk-OD5XLL3O.js";
7
- import "./chunk-34E5PYNA.js";
3
+ } from "./chunk-JS5Y2DTW.js";
8
4
  import {
9
5
  buildPublicUrl,
10
6
  normalizeUrlLike
11
7
  } from "./chunk-3NJASEF4.js";
8
+ import {
9
+ parseJwtPayload
10
+ } from "./chunk-OD5XLL3O.js";
11
+ import "./chunk-34E5PYNA.js";
12
12
 
13
13
  // src/edge.ts
14
14
  import { headers } from "next/headers";
package/dist/index.d.ts CHANGED
@@ -3,5 +3,5 @@ export { OidcHumanResolverConfig, createOidcHumanResolver } from './oidc-human.j
3
3
  export { OidcAuthUrlConfig, PkceChallenge, buildOidcAuthUrl, generatePkce } from './pkce.js';
4
4
  export { CliAuthResult, CliAuthStart, PollOptions, pollCliAuth, startCliAuth } from './cli-auth.js';
5
5
  export { hashToken, looksLikeJwt, stripBearer } from './token.js';
6
- export { JwtClaims, verifyHs256Jwt } from './jwt.js';
6
+ export { JwtClaims, signHs256Jwt, verifyHs256Jwt } from './jwt.js';
7
7
  export { buildAccountProfileUrl, buildAuthLoginUrl, buildAuthLogoutUrl, buildPublicUrl, getAccountPublicUrl, getAppBasePath, getAuthPublicUrl, getPublicSiteUrl, normalizeUrlLike } from './url-helpers.js';
package/dist/index.js CHANGED
@@ -13,13 +13,6 @@ import {
13
13
  looksLikeJwt,
14
14
  stripBearer
15
15
  } from "./chunk-VBIQJKUU.js";
16
- import {
17
- verifyHs256Jwt
18
- } from "./chunk-OD5XLL3O.js";
19
- import {
20
- buildOidcAuthUrl,
21
- generatePkce
22
- } from "./chunk-34E5PYNA.js";
23
16
  import {
24
17
  buildAccountProfileUrl,
25
18
  buildAuthLoginUrl,
@@ -31,6 +24,14 @@ import {
31
24
  getPublicSiteUrl,
32
25
  normalizeUrlLike
33
26
  } from "./chunk-3NJASEF4.js";
27
+ import {
28
+ signHs256Jwt,
29
+ verifyHs256Jwt
30
+ } from "./chunk-OD5XLL3O.js";
31
+ import {
32
+ buildOidcAuthUrl,
33
+ generatePkce
34
+ } from "./chunk-34E5PYNA.js";
34
35
  export {
35
36
  buildAccountProfileUrl,
36
37
  buildAuthLoginUrl,
@@ -47,6 +48,7 @@ export {
47
48
  looksLikeJwt,
48
49
  normalizeUrlLike,
49
50
  pollCliAuth,
51
+ signHs256Jwt,
50
52
  startCliAuth,
51
53
  stripBearer,
52
54
  verifyHs256Jwt,
package/dist/session.js CHANGED
@@ -9,10 +9,10 @@ import {
9
9
  handleAuthorizationCallback,
10
10
  hasServerOidcSession,
11
11
  oidcCookies
12
- } from "./chunk-5W4TEXCT.js";
12
+ } from "./chunk-JS5Y2DTW.js";
13
+ import "./chunk-3NJASEF4.js";
13
14
  import "./chunk-OD5XLL3O.js";
14
15
  import "./chunk-34E5PYNA.js";
15
- import "./chunk-3NJASEF4.js";
16
16
  export {
17
17
  buildAuthorizationRedirect,
18
18
  buildLogoutResponse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baseworks/auth",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dist/index.js",
@@ -8,6 +8,7 @@
8
8
  "./oidc-human": "./dist/oidc-human.js",
9
9
  "./pkce": "./dist/pkce.js",
10
10
  "./cli-auth": "./dist/cli-auth.js",
11
+ "./cli": "./dist/cli.js",
11
12
  "./token": "./dist/token.js",
12
13
  "./session": "./dist/session.js",
13
14
  "./url-helpers": "./dist/url-helpers.js",
@@ -40,8 +41,10 @@
40
41
  }
41
42
  },
42
43
  "devDependencies": {
44
+ "@baseworks/cli": "workspace:*",
43
45
  "@baseworks/tsconfig": "workspace:*",
44
46
  "@types/node": "^26.0.1",
47
+ "commander": "^15.0.0",
45
48
  "hono": "^4.12.27",
46
49
  "tsup": "^8.5.1",
47
50
  "typescript": "^5.6.0"
package/src/cli.ts ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Importable `login` / `logout` commands for any CLI that authenticates through
3
+ * an auth-service (OIDC/PKCE device flow). Mirrors the `@baseworks/org/cli` and
4
+ * `@baseworks/iam/cli` pattern — the commands live in auth's own package; the
5
+ * app composes them:
6
+ *
7
+ * import { addAuthCommands } from '@baseworks/auth/cli'
8
+ * addAuthCommands(program, { authBase, cliName: 'dtab', onToken, onLogout })
9
+ *
10
+ * The device flow is auth-service's `/v1/auth/start` + `/v1/auth/poll/:state`
11
+ * (see `@baseworks/auth/cli-auth`). auth mints an identity JWT (`{ sub, type }`,
12
+ * HS256) that org-service and iam-service verify with the shared realm secret —
13
+ * so ONE login token works across the whole plane. Org context is not in the
14
+ * token; the app resolves it via org-service (`use` / `ls`).
15
+ */
16
+ import { spawn } from 'node:child_process'
17
+ import { Command } from 'commander'
18
+ import { clr, kv, success, warn, fatal } from '@baseworks/cli/display'
19
+ import { startCliAuth, pollCliAuth } from './cli-auth.js'
20
+
21
+ export interface AuthCliDeps {
22
+ /** Origin of the auth mount, e.g. `http://127.0.0.1:3003` (no `/v1/auth`). */
23
+ authBase: string | (() => string)
24
+ cliName?: string
25
+ /** Persist the identity token (app decides where). */
26
+ onToken: (token: string) => void | Promise<void>
27
+ /** Clear persisted credentials/context. */
28
+ onLogout?: () => void | Promise<void>
29
+ /** Open the browser automatically (default true). */
30
+ openBrowser?: boolean
31
+ }
32
+
33
+ function resolveBase(b: AuthCliDeps['authBase']): string {
34
+ return (typeof b === 'function' ? b() : b).replace(/\/+$/, '')
35
+ }
36
+
37
+ function openInBrowser(url: string): void {
38
+ const cmd = process.platform === 'darwin' ? 'open'
39
+ : process.platform === 'win32' ? 'cmd'
40
+ : 'xdg-open'
41
+ const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url]
42
+ try { spawn(cmd, args, { stdio: 'ignore', detached: true }).unref() } catch { /* print fallback below */ }
43
+ }
44
+
45
+ /** Decode a JWT payload without verifying (display only). */
46
+ function jwtSub(token: string): string | undefined {
47
+ try {
48
+ const seg = token.split('.')[1]
49
+ if (!seg) return undefined
50
+ const json = Buffer.from(seg.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8')
51
+ return (JSON.parse(json) as { sub?: string }).sub
52
+ } catch { return undefined }
53
+ }
54
+
55
+ export function addAuthCommands(program: Command, deps: AuthCliDeps): void {
56
+ const cli = deps.cliName ?? 'cli'
57
+
58
+ program.addCommand(
59
+ new Command('login')
60
+ .description('Log in via browser (OIDC/PKCE)')
61
+ .option('--no-open', 'Do not open the browser automatically')
62
+ .action(async (opts: { open?: boolean }) => {
63
+ const base = resolveBase(deps.authBase)
64
+ const start = await startCliAuth(base).catch((e: Error) => fatal(`Could not reach auth service at ${base}: ${e.message}`))
65
+
66
+ console.log(`\n ${clr.dim}Opening your browser to sign in…${clr.reset}`)
67
+ console.log(` ${clr.dim}If it does not open, visit:${clr.reset}\n ${clr.cyan}${start.url}${clr.reset}\n`)
68
+ if (deps.openBrowser !== false && opts.open !== false) openInBrowser(start.url)
69
+
70
+ const { token } = await pollCliAuth(base, start.state).catch((e: Error) => fatal(e.message))
71
+ await deps.onToken(token)
72
+
73
+ const sub = jwtSub(token)
74
+ success('Logged in.')
75
+ if (sub) kv([['user id', sub]])
76
+ console.log(` ${clr.dim}Next: ${cli} use · ${cli} orgs${clr.reset}\n`)
77
+ }),
78
+ )
79
+
80
+ program.addCommand(
81
+ new Command('logout')
82
+ .description('Clear saved credentials and active context')
83
+ .action(async () => {
84
+ if (deps.onLogout) await deps.onLogout()
85
+ else warn('No logout handler configured.')
86
+ success('Logged out.')
87
+ }),
88
+ )
89
+ }
package/src/index.ts CHANGED
@@ -17,8 +17,8 @@ export type { CliAuthStart, CliAuthResult, PollOptions } from './cli-auth';
17
17
  // Token utilities
18
18
  export { hashToken, looksLikeJwt, stripBearer } from './token';
19
19
 
20
- // HS256 JWT verification (Node.js)
21
- export { verifyHs256Jwt } from './jwt';
20
+ // HS256 JWT sign + verify (Node.js)
21
+ export { signHs256Jwt, verifyHs256Jwt } from './jwt';
22
22
  export type { JwtClaims } from './jwt';
23
23
 
24
24
  // URL helpers (auth/account public URLs, login/logout URL builders)
@@ -1,13 +1,13 @@
1
+ import {
2
+ getAuthPublicUrl,
3
+ normalizeUrlLike
4
+ } from "./chunk-3NJASEF4.js";
1
5
  import {
2
6
  parseJwtPayload
3
7
  } from "./chunk-OD5XLL3O.js";
4
8
  import {
5
9
  generatePkce
6
10
  } from "./chunk-34E5PYNA.js";
7
- import {
8
- getAuthPublicUrl,
9
- normalizeUrlLike
10
- } from "./chunk-3NJASEF4.js";
11
11
 
12
12
  // src/session.ts
13
13
  import { cookies } from "next/headers";