@tillstack/cli 0.3.1 → 0.3.2

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/index.js CHANGED
@@ -340,6 +340,11 @@ ${c.bold('TILLAUTH')} ${c.dim('(auth)')} ${c.gray('tilldev auth …')
340
340
  auth apps create <name> [--slug <s>] Create an auth app
341
341
  auth app <appRef> Show an auth app (by slug or id)
342
342
  auth invite <appRef> <email> [--role <r>] Invite a user to an app
343
+ auth clients <appRef> List OIDC clients registered on an app
344
+ auth clients <appRef> create <name> --redirect <uri>[,<uri>] [--scopes …] [--public] [--no-consent]
345
+ auth clients <appRef> rm <clientId> Remove an OIDC client
346
+ auth scim <appRef> [rotate] Mint/rotate the SCIM provisioning token (shown once)
347
+ auth scim <appRef> disable Turn SCIM provisioning off
343
348
 
344
349
  ${c.bold('WORKSPACE')}
345
350
  team List org members
@@ -777,6 +782,77 @@ async function cmdAuth(flags) {
777
782
  });
778
783
  return;
779
784
  }
785
+ case 'clients': {
786
+ const appRef = need(flags.positional[2], 'tilldev auth clients <appRef> [create|rm]');
787
+ const action = flags.positional[3];
788
+ if (action === 'create') {
789
+ const name = need(flags.positional[4], 'tilldev auth clients <appRef> create <name> --redirect <uri>[,<uri>…] [--scopes openid,email,profile] [--public] [--no-consent]');
790
+ // Comma-separate multiple redirect URIs in a single --redirect flag.
791
+ const redirect_uris = (flags.named['redirect'] ?? '').split(',').map((s) => s.trim()).filter(Boolean);
792
+ if (redirect_uris.length === 0)
793
+ throw new Error('At least one --redirect <uri> is required');
794
+ const scopes = flags.named['scopes']?.split(',').map((s) => s.trim()).filter(Boolean);
795
+ const body = {
796
+ name,
797
+ redirect_uris,
798
+ ...(scopes ? { scopes } : {}),
799
+ ...(flags.bool.has('public') ? { public: true } : {}),
800
+ ...(flags.bool.has('no-consent') ? { require_consent: false } : {}),
801
+ };
802
+ const r = await api.createOidcClient(opts, appRef, body);
803
+ render(flags, r, () => {
804
+ ok(`Registered OIDC client ${c.bold(r.client_id)} (${c.dim(r.client_type)})`);
805
+ console.log(kv([
806
+ ['client_id', r.client_id],
807
+ ['redirect_uris', r.redirect_uris.join(', ')],
808
+ ['scopes', r.scopes.join(' ')],
809
+ ]));
810
+ if (r.client_secret) {
811
+ console.log(`\n${c.yellow('client_secret (shown once — store it now):')}\n ${c.bold(r.client_secret)}`);
812
+ }
813
+ else {
814
+ console.log(c.dim('\nPublic client — no secret; authenticate with PKCE (S256).'));
815
+ }
816
+ });
817
+ return;
818
+ }
819
+ if (action === 'rm' || action === 'delete') {
820
+ const clientId = need(flags.positional[4], 'tilldev auth clients <appRef> rm <clientId>');
821
+ const r = await api.deleteOidcClient(opts, appRef, clientId);
822
+ render(flags, r, () => ok(`Removed client ${c.dim(clientId)}`));
823
+ return;
824
+ }
825
+ const r = await api.listOidcClients(opts, appRef);
826
+ render(flags, r, () => {
827
+ const cols = [
828
+ { header: 'CLIENT ID', get: (x) => c.bold(x.client_id) },
829
+ { header: 'NAME', get: (x) => x.name },
830
+ { header: 'TYPE', get: (x) => c.dim(x.client_type) },
831
+ { header: 'SCOPES', get: (x) => (x.scopes ?? []).join(' ') },
832
+ { header: 'ENABLED', get: (x) => (x.enabled ? c.green('yes') : c.red('no')) },
833
+ ];
834
+ console.log(table(r.clients, cols));
835
+ });
836
+ return;
837
+ }
838
+ case 'scim': {
839
+ const appRef = need(flags.positional[2], 'tilldev auth scim <appRef> [rotate|disable]');
840
+ const action = flags.positional[3] ?? 'rotate';
841
+ if (action === 'disable') {
842
+ const r = await api.scimDisable(opts, appRef);
843
+ render(flags, r, () => ok('SCIM provisioning disabled for this app.'));
844
+ return;
845
+ }
846
+ // rotate (also the enable path — mints a fresh token, shown once)
847
+ const r = await api.scimRotate(opts, appRef);
848
+ render(flags, r, () => {
849
+ ok('SCIM provisioning token minted.');
850
+ console.log(kv([['scim_base_url', r.scim_base_url]]));
851
+ console.log(`\n${c.yellow('bearer token (shown once — store it now):')}\n ${c.bold(r.token)}`);
852
+ console.log(c.dim('\nConfigure your IdP (Okta, Entra ID, …) with the base URL + this token.'));
853
+ });
854
+ return;
855
+ }
780
856
  default:
781
857
  throw new Error(`unknown: tilldev auth ${sub}`);
782
858
  }