@geolonia/geonicdb-cli 0.6.4 → 0.7.0
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 +19 -3
- package/dist/index.js +72 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -213,12 +213,16 @@ Displays the current authenticated user, token expiry, and active profile.
|
|
|
213
213
|
| `--entity-types <types>` | Allowed entity types (comma-separated) |
|
|
214
214
|
| `--rate-limit <n>` | Rate limit (requests per minute) |
|
|
215
215
|
| `--dpop-required` | Require DPoP token binding (RFC 9449) |
|
|
216
|
+
| `--permissions <perms>` | Permissions for auto-generated XACML policy (comma-separated) |
|
|
216
217
|
| `--save` | Save the API key to profile config |
|
|
217
218
|
|
|
218
219
|
```bash
|
|
219
220
|
# Create an API key and save to config
|
|
220
221
|
geonic me api-keys create --name my-app --scopes read:entities --save
|
|
221
222
|
|
|
223
|
+
# Create with permissions (auto-generates XACML policy)
|
|
224
|
+
geonic me api-keys create --name my-app --permissions read,write --save
|
|
225
|
+
|
|
222
226
|
# Create from JSON
|
|
223
227
|
geonic me api-keys create '{"name":"my-app","allowedScopes":["read:entities"]}'
|
|
224
228
|
```
|
|
@@ -392,6 +396,16 @@ Temporal entityOperations query supports: `--aggr-methods`, `--aggr-period`.
|
|
|
392
396
|
| `admin policies activate <id>` | Activate a policy |
|
|
393
397
|
| `admin policies deactivate <id>` | Deactivate a policy |
|
|
394
398
|
|
|
399
|
+
**XACML Authorization Model**: All authorization is unified under XACML policies. Default role policies (priority 0):
|
|
400
|
+
|
|
401
|
+
| Role | Default Behavior |
|
|
402
|
+
|---|---|
|
|
403
|
+
| `user` | GET only (read-only) |
|
|
404
|
+
| `api_key` | All Deny |
|
|
405
|
+
| `anonymous` | All Deny |
|
|
406
|
+
|
|
407
|
+
Custom policies with higher priority (e.g. 100) override defaults. Target resource attributes include: `path`, `entityType`, `entityId`, `entityOwner`, `tenantService`, `servicePath`. The `servicePath` attribute supports glob patterns (e.g. `/opendata/**`) and regex matching.
|
|
408
|
+
|
|
395
409
|
#### admin oauth-clients
|
|
396
410
|
|
|
397
411
|
| Subcommand | Description |
|
|
@@ -412,7 +426,9 @@ Temporal entityOperations query supports: `--aggr-methods`, `--aggr-period`.
|
|
|
412
426
|
| `admin api-keys update <keyId> [json]` | Update an API key |
|
|
413
427
|
| `admin api-keys delete <keyId>` | Delete an API key |
|
|
414
428
|
|
|
415
|
-
`admin api-keys list` supports `--tenant-id` to filter by tenant. `admin api-keys create` supports flag options: `--name`, `--scopes`, `--origins`, `--entity-types`, `--rate-limit`, `--dpop-required`, `--tenant-id`, `--save`. `admin api-keys update` supports `--name`, `--scopes`, `--origins`, `--entity-types`, `--rate-limit`, `--dpop-required` / `--no-dpop-required`.
|
|
429
|
+
`admin api-keys list` supports `--tenant-id` to filter by tenant. `admin api-keys create` supports flag options: `--name`, `--scopes`, `--origins`, `--entity-types`, `--rate-limit`, `--dpop-required`, `--permissions`, `--tenant-id`, `--save`. `admin api-keys update` supports `--name`, `--scopes`, `--origins`, `--entity-types`, `--rate-limit`, `--dpop-required` / `--no-dpop-required`, `--permissions`.
|
|
430
|
+
|
|
431
|
+
**Permissions**: The `--permissions` flag accepts a comma-separated list of `read`, `write`, `create`, `update`, `delete`. `write` is an alias for `create` + `update` + `delete`. When specified, XACML policies are auto-generated for the API key (respects `allowedEntityTypes`).
|
|
416
432
|
|
|
417
433
|
**Note**: `allowedOrigins` must contain at least 1 item when specified. Use `*` to allow all origins. `allowedEntityTypes` is enforced at runtime — API key holders can only access entities of the specified types. `admin api-keys list` / `admin api-keys get` output includes a `dpopRequired` field (boolean).
|
|
418
434
|
|
|
@@ -560,13 +576,13 @@ geonic entities list --api-key gdb_your_api_key_here
|
|
|
560
576
|
GDB_API_KEY=gdb_your_api_key_here geonic entities list
|
|
561
577
|
```
|
|
562
578
|
|
|
563
|
-
When both a Bearer token and an API key are configured,
|
|
579
|
+
When both a Bearer token and an API key are configured, headers are sent exclusively — the API key takes precedence when present.
|
|
564
580
|
|
|
565
581
|
### Valid Scopes
|
|
566
582
|
|
|
567
583
|
`read:entities`, `write:entities`, `read:subscriptions`, `write:subscriptions`, `read:registrations`, `write:registrations`, `read:rules`, `write:rules`, `read:custom-data-models`, `write:custom-data-models`, `admin:users`, `admin:tenants`, `admin:policies`, `admin:oauth-clients`, `admin:api-keys`, `admin:metrics`
|
|
568
584
|
|
|
569
|
-
`
|
|
585
|
+
`admin:X` implies both `read:X` and `write:X`. `write:X` does **not** imply `read:X` — specify both explicitly if needed.
|
|
570
586
|
|
|
571
587
|
Special scopes: `permanent` (no token expiry), `jwt` (JWT format token).
|
|
572
588
|
|
package/dist/index.js
CHANGED
|
@@ -945,13 +945,23 @@ var SCOPES_HELP_NOTES = [
|
|
|
945
945
|
" admin:users, admin:tenants, admin:policies, admin:oauth-clients,",
|
|
946
946
|
" admin:api-keys, admin:metrics",
|
|
947
947
|
"",
|
|
948
|
-
"
|
|
948
|
+
"admin:X implies both read:X and write:X.",
|
|
949
|
+
"write:X does NOT imply read:X \u2014 specify both if needed."
|
|
949
950
|
];
|
|
950
951
|
var API_KEY_SCOPES_HELP_NOTES = [
|
|
951
952
|
"Valid scopes:",
|
|
952
953
|
" read:entities, write:entities, read:subscriptions, write:subscriptions,",
|
|
953
954
|
" read:registrations, write:registrations"
|
|
954
955
|
];
|
|
956
|
+
var VALID_PERMISSIONS = /* @__PURE__ */ new Set(["read", "write", "create", "update", "delete"]);
|
|
957
|
+
function parsePermissions(raw) {
|
|
958
|
+
const permissions = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
959
|
+
if (permissions.length === 0 || permissions.some((p) => !VALID_PERMISSIONS.has(p))) {
|
|
960
|
+
printError("--permissions must be a comma-separated list of: read, write, create, update, delete");
|
|
961
|
+
process.exit(1);
|
|
962
|
+
}
|
|
963
|
+
return permissions;
|
|
964
|
+
}
|
|
955
965
|
function resolveOptions(cmd) {
|
|
956
966
|
const opts = cmd.optsWithGlobals();
|
|
957
967
|
const config = loadConfig(opts.profile);
|
|
@@ -1426,7 +1436,7 @@ function addMeApiKeysSubcommand(me) {
|
|
|
1426
1436
|
command: "geonic me api-keys list"
|
|
1427
1437
|
}
|
|
1428
1438
|
]);
|
|
1429
|
-
const create = apiKeys.command("create [json]").description("Create a new API key").option("--name <name>", "Key name").option("--scopes <scopes>", "Allowed scopes (comma-separated)").option("--origins <origins>", "Allowed origins (comma-separated)").option("--entity-types <types>", "Allowed entity types (comma-separated)").option("--rate-limit <n>", "Rate limit per minute").option("--dpop-required", "Require DPoP token binding").option("--save", "Save the API key to config for automatic use").action(
|
|
1439
|
+
const create = apiKeys.command("create [json]").description("Create a new API key").option("--name <name>", "Key name").option("--scopes <scopes>", "Allowed scopes (comma-separated)").option("--origins <origins>", "Allowed origins (comma-separated)").option("--entity-types <types>", "Allowed entity types (comma-separated)").option("--rate-limit <n>", "Rate limit per minute").option("--dpop-required", "Require DPoP token binding").option("--permissions <perms>", "Comma-separated permissions (read, write, create, update, delete)").option("--save", "Save the API key to config for automatic use").action(
|
|
1430
1440
|
withErrorHandler(async (json, _opts, cmd) => {
|
|
1431
1441
|
const opts = cmd.opts();
|
|
1432
1442
|
if (opts.origins !== void 0) {
|
|
@@ -1439,13 +1449,14 @@ function addMeApiKeysSubcommand(me) {
|
|
|
1439
1449
|
let body;
|
|
1440
1450
|
if (json) {
|
|
1441
1451
|
body = await parseJsonInput(json);
|
|
1442
|
-
} else if (opts.name || opts.scopes || opts.origins || opts.entityTypes || opts.rateLimit || opts.dpopRequired !== void 0) {
|
|
1452
|
+
} else if (opts.name || opts.scopes || opts.origins || opts.entityTypes || opts.rateLimit || opts.dpopRequired !== void 0 || opts.permissions) {
|
|
1443
1453
|
const payload = {};
|
|
1444
1454
|
if (opts.name) payload.name = opts.name;
|
|
1445
1455
|
if (opts.scopes) payload.allowedScopes = opts.scopes.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1446
1456
|
if (opts.origins) payload.allowedOrigins = opts.origins.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1447
1457
|
if (opts.entityTypes) payload.allowedEntityTypes = opts.entityTypes.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1448
1458
|
if (opts.dpopRequired !== void 0) payload.dpopRequired = opts.dpopRequired;
|
|
1459
|
+
if (opts.permissions) payload.permissions = parsePermissions(opts.permissions);
|
|
1449
1460
|
if (opts.rateLimit) {
|
|
1450
1461
|
const raw = opts.rateLimit.trim();
|
|
1451
1462
|
if (!/^\d+$/.test(raw)) {
|
|
@@ -1494,12 +1505,22 @@ function addMeApiKeysSubcommand(me) {
|
|
|
1494
1505
|
console.error("API key created.");
|
|
1495
1506
|
})
|
|
1496
1507
|
);
|
|
1497
|
-
addNotes(create,
|
|
1508
|
+
addNotes(create, [
|
|
1509
|
+
...API_KEY_SCOPES_HELP_NOTES,
|
|
1510
|
+
"",
|
|
1511
|
+
"Valid permissions: read, write, create, update, delete",
|
|
1512
|
+
" write = create + update + delete",
|
|
1513
|
+
" Permissions auto-generate XACML policies (allowedEntityTypes respected)."
|
|
1514
|
+
]);
|
|
1498
1515
|
addExamples(create, [
|
|
1499
1516
|
{
|
|
1500
1517
|
description: "Create an API key with flags",
|
|
1501
1518
|
command: "geonic me api-keys create --name my-app --scopes read:entities --origins 'https://example.com'"
|
|
1502
1519
|
},
|
|
1520
|
+
{
|
|
1521
|
+
description: "Create with permissions (auto-generates XACML policy)",
|
|
1522
|
+
command: "geonic me api-keys create --name my-app --permissions read,write --save"
|
|
1523
|
+
},
|
|
1503
1524
|
{
|
|
1504
1525
|
description: "Create and save API key to config",
|
|
1505
1526
|
command: "geonic me api-keys create --name my-app --save"
|
|
@@ -3201,7 +3222,7 @@ function registerUsersCommand(parent) {
|
|
|
3201
3222
|
}
|
|
3202
3223
|
]);
|
|
3203
3224
|
const create = users.command("create [json]").description(
|
|
3204
|
-
'Create a new user\n\nJSON payload example:\n {\n "email": "user@example.com",\n "password": "SecurePassword123!",\n "role": "
|
|
3225
|
+
'Create a new user\n\nJSON payload example:\n {\n "email": "user@example.com",\n "password": "SecurePassword123!",\n "role": "tenant_admin",\n "tenantId": "<tenant-id>"\n }\n\nRoles: super_admin, tenant_admin, user\ntenantId is required for tenant_admin and user roles.'
|
|
3205
3226
|
).action(
|
|
3206
3227
|
withErrorHandler(async (json, _opts, cmd) => {
|
|
3207
3228
|
const body = await parseJsonInput(json);
|
|
@@ -3216,8 +3237,12 @@ function registerUsersCommand(parent) {
|
|
|
3216
3237
|
);
|
|
3217
3238
|
addExamples(create, [
|
|
3218
3239
|
{
|
|
3219
|
-
description: "Create
|
|
3220
|
-
command: `geonic admin users create '{"email":"
|
|
3240
|
+
description: "Create a tenant admin",
|
|
3241
|
+
command: `geonic admin users create '{"email":"admin@example.com","password":"SecurePass12345!","role":"tenant_admin","tenantId":"<tenant-id>"}'`
|
|
3242
|
+
},
|
|
3243
|
+
{
|
|
3244
|
+
description: "Create a user for a tenant",
|
|
3245
|
+
command: `geonic admin users create '{"email":"user@example.com","password":"SecurePass12345!","role":"user","tenantId":"<tenant-id>"}'`
|
|
3221
3246
|
},
|
|
3222
3247
|
{
|
|
3223
3248
|
description: "Create from a JSON file",
|
|
@@ -3361,7 +3386,7 @@ function registerPoliciesCommand(parent) {
|
|
|
3361
3386
|
}
|
|
3362
3387
|
]);
|
|
3363
3388
|
const create = policies.command("create [json]").description(
|
|
3364
|
-
'Create a new policy\n\nJSON payload
|
|
3389
|
+
'Create a new policy\n\nJSON payload examples:\n\n Allow all entities:\n {\n "description": "Allow all entities",\n "rules": [{"ruleId": "allow-all", "effect": "Permit"}]\n }\n\n Allow GET access to a specific entity type:\n {\n "description": "Allow GET access to Landmark entities",\n "target": {\n "resources": [{"attributeId": "entityType", "matchValue": "Landmark"}],\n "actions": [{"attributeId": "method", "matchValue": "GET"}]\n },\n "rules": [{"ruleId": "permit-get", "effect": "Permit"}]\n }\n\nTarget fields:\n subjects \u2014 attributeId: role, userId, email, tenantId\n resources \u2014 attributeId: path, entityType, entityId, entityOwner, tenantService, servicePath\n actions \u2014 attributeId: method (GET, POST, PATCH, DELETE)\n\nEach element: {attributeId, matchValue, matchFunction?}\n matchFunction: "string-equal" (default) | "string-regexp" | "glob"\n\nPriority: higher number = higher priority (default: 0).\n Custom policies (e.g. 100) override default role policies (0).\n\nDefault role policies (priority 0):\n user \u2192 GET only, api_key \u2192 all Deny, anonymous \u2192 all Deny'
|
|
3365
3390
|
).action(
|
|
3366
3391
|
withErrorHandler(async (json, _opts, cmd) => {
|
|
3367
3392
|
const body = await parseJsonInput(json);
|
|
@@ -3379,6 +3404,18 @@ function registerPoliciesCommand(parent) {
|
|
|
3379
3404
|
description: "Create with inline JSON",
|
|
3380
3405
|
command: `geonic admin policies create '{"description":"Allow all entities","rules":[{"ruleId":"allow-all","effect":"Permit"}]}'`
|
|
3381
3406
|
},
|
|
3407
|
+
{
|
|
3408
|
+
description: "Create with target (entity type + method)",
|
|
3409
|
+
command: `geonic admin policies create '{"description":"Allow GET Landmark","target":{"resources":[{"attributeId":"entityType","matchValue":"Landmark"}],"actions":[{"attributeId":"method","matchValue":"GET"}]},"rules":[{"ruleId":"permit-get","effect":"Permit"}]}'`
|
|
3410
|
+
},
|
|
3411
|
+
{
|
|
3412
|
+
description: "Create anonymous access policy",
|
|
3413
|
+
command: `geonic admin policies create '{"policyId":"public-read","target":{"subjects":[{"attributeId":"role","matchValue":"anonymous"}],"resources":[{"attributeId":"entityType","matchValue":"WeatherObserved"}],"actions":[{"attributeId":"method","matchValue":"GET"}]},"rules":[{"effect":"Permit"}]}'`
|
|
3414
|
+
},
|
|
3415
|
+
{
|
|
3416
|
+
description: "Create servicePath-based policy (glob match)",
|
|
3417
|
+
command: `geonic admin policies create '{"description":"Allow read on /opendata/**","priority":100,"target":{"resources":[{"attributeId":"servicePath","matchValue":"/opendata/**","matchFunction":"glob"}],"actions":[{"attributeId":"method","matchValue":"GET"}]},"rules":[{"effect":"Permit"}]}'`
|
|
3418
|
+
},
|
|
3382
3419
|
{
|
|
3383
3420
|
description: "Create from a JSON file",
|
|
3384
3421
|
command: "geonic admin policies create @policy.json"
|
|
@@ -3677,6 +3714,7 @@ function buildBodyFromFlags(opts) {
|
|
|
3677
3714
|
payload.rateLimit = { perMinute };
|
|
3678
3715
|
}
|
|
3679
3716
|
if (opts.dpopRequired !== void 0) payload.dpopRequired = opts.dpopRequired;
|
|
3717
|
+
if (opts.permissions) payload.permissions = parsePermissions(opts.permissions);
|
|
3680
3718
|
if (opts.tenantId) payload.tenantId = opts.tenantId;
|
|
3681
3719
|
return payload;
|
|
3682
3720
|
}
|
|
@@ -3722,14 +3760,14 @@ function registerApiKeysCommand(parent) {
|
|
|
3722
3760
|
command: "geonic admin api-keys get <key-id>"
|
|
3723
3761
|
}
|
|
3724
3762
|
]);
|
|
3725
|
-
const create = apiKeys.command("create [json]").description("Create a new API key").option("--name <name>", "Key name").option("--scopes <scopes>", "Comma-separated scopes").option("--origins <origins>", "Comma-separated origins").option("--entity-types <types>", "Comma-separated entity types").option("--rate-limit <n>", "Rate limit per minute").option("--dpop-required", "Require DPoP token binding").option("--tenant-id <id>", "Tenant ID").option("--save", "Save the API key to profile config").action(
|
|
3763
|
+
const create = apiKeys.command("create [json]").description("Create a new API key").option("--name <name>", "Key name").option("--scopes <scopes>", "Comma-separated scopes").option("--origins <origins>", "Comma-separated origins").option("--entity-types <types>", "Comma-separated entity types").option("--rate-limit <n>", "Rate limit per minute").option("--dpop-required", "Require DPoP token binding").option("--permissions <perms>", "Comma-separated permissions (read, write, create, update, delete)").option("--tenant-id <id>", "Tenant ID").option("--save", "Save the API key to profile config").action(
|
|
3726
3764
|
withErrorHandler(async (json, _opts, cmd) => {
|
|
3727
3765
|
const opts = cmd.opts();
|
|
3728
3766
|
validateOrigins(void 0, opts);
|
|
3729
3767
|
let body;
|
|
3730
3768
|
if (json) {
|
|
3731
3769
|
body = await parseJsonInput(json);
|
|
3732
|
-
} else if (opts.name || opts.scopes || opts.origins || opts.entityTypes || opts.rateLimit || opts.dpopRequired !== void 0 || opts.tenantId) {
|
|
3770
|
+
} else if (opts.name || opts.scopes || opts.origins || opts.entityTypes || opts.rateLimit || opts.dpopRequired !== void 0 || opts.permissions || opts.tenantId) {
|
|
3733
3771
|
body = buildBodyFromFlags(opts);
|
|
3734
3772
|
} else {
|
|
3735
3773
|
body = await parseJsonInput();
|
|
@@ -3761,12 +3799,22 @@ function registerApiKeysCommand(parent) {
|
|
|
3761
3799
|
console.error("API key created.");
|
|
3762
3800
|
})
|
|
3763
3801
|
);
|
|
3764
|
-
addNotes(create,
|
|
3802
|
+
addNotes(create, [
|
|
3803
|
+
...API_KEY_SCOPES_HELP_NOTES,
|
|
3804
|
+
"",
|
|
3805
|
+
"Valid permissions: read, write, create, update, delete",
|
|
3806
|
+
" write = create + update + delete",
|
|
3807
|
+
" Permissions auto-generate XACML policies (allowedEntityTypes respected)."
|
|
3808
|
+
]);
|
|
3765
3809
|
addExamples(create, [
|
|
3766
3810
|
{
|
|
3767
3811
|
description: "Create an API key with flags",
|
|
3768
3812
|
command: "geonic admin api-keys create --name my-key --scopes read:entities,write:entities --origins '*'"
|
|
3769
3813
|
},
|
|
3814
|
+
{
|
|
3815
|
+
description: "Create with permissions (auto-generates XACML policy)",
|
|
3816
|
+
command: "geonic admin api-keys create --name my-key --permissions read,write --origins '*'"
|
|
3817
|
+
},
|
|
3770
3818
|
{
|
|
3771
3819
|
description: "Create an API key with DPoP required",
|
|
3772
3820
|
command: "geonic admin api-keys create --name my-key --dpop-required"
|
|
@@ -3776,7 +3824,7 @@ function registerApiKeysCommand(parent) {
|
|
|
3776
3824
|
command: "geonic admin api-keys create @key.json --save"
|
|
3777
3825
|
}
|
|
3778
3826
|
]);
|
|
3779
|
-
const update = apiKeys.command("update <keyId> [json]").description("Update an API key").option("--name <name>", "Key name").option("--scopes <scopes>", "Comma-separated scopes").option("--origins <origins>", "Comma-separated origins").option("--entity-types <types>", "Comma-separated entity types").option("--rate-limit <n>", "Rate limit per minute").option("--dpop-required", "Require DPoP token binding").option("--no-dpop-required", "Disable DPoP token binding").action(
|
|
3827
|
+
const update = apiKeys.command("update <keyId> [json]").description("Update an API key").option("--name <name>", "Key name").option("--scopes <scopes>", "Comma-separated scopes").option("--origins <origins>", "Comma-separated origins").option("--entity-types <types>", "Comma-separated entity types").option("--rate-limit <n>", "Rate limit per minute").option("--dpop-required", "Require DPoP token binding").option("--no-dpop-required", "Disable DPoP token binding").option("--permissions <perms>", "Comma-separated permissions (read, write, create, update, delete)").action(
|
|
3780
3828
|
withErrorHandler(
|
|
3781
3829
|
async (keyId, json, _opts, cmd) => {
|
|
3782
3830
|
const opts = cmd.opts();
|
|
@@ -3784,7 +3832,7 @@ function registerApiKeysCommand(parent) {
|
|
|
3784
3832
|
let body;
|
|
3785
3833
|
if (json) {
|
|
3786
3834
|
body = await parseJsonInput(json);
|
|
3787
|
-
} else if (opts.name || opts.scopes || opts.origins || opts.entityTypes || opts.rateLimit || opts.dpopRequired !== void 0) {
|
|
3835
|
+
} else if (opts.name || opts.scopes || opts.origins || opts.entityTypes || opts.rateLimit || opts.dpopRequired !== void 0 || opts.permissions) {
|
|
3788
3836
|
body = buildBodyFromFlags(opts);
|
|
3789
3837
|
} else {
|
|
3790
3838
|
body = await parseJsonInput();
|
|
@@ -3802,12 +3850,22 @@ function registerApiKeysCommand(parent) {
|
|
|
3802
3850
|
}
|
|
3803
3851
|
)
|
|
3804
3852
|
);
|
|
3805
|
-
addNotes(update,
|
|
3853
|
+
addNotes(update, [
|
|
3854
|
+
...API_KEY_SCOPES_HELP_NOTES,
|
|
3855
|
+
"",
|
|
3856
|
+
"Valid permissions: read, write, create, update, delete",
|
|
3857
|
+
" write = create + update + delete",
|
|
3858
|
+
" Permissions auto-generate XACML policies (allowedEntityTypes respected)."
|
|
3859
|
+
]);
|
|
3806
3860
|
addExamples(update, [
|
|
3807
3861
|
{
|
|
3808
3862
|
description: "Update an API key name",
|
|
3809
3863
|
command: "geonic admin api-keys update <key-id> --name new-name"
|
|
3810
3864
|
},
|
|
3865
|
+
{
|
|
3866
|
+
description: "Update permissions",
|
|
3867
|
+
command: "geonic admin api-keys update <key-id> --permissions read,write"
|
|
3868
|
+
},
|
|
3811
3869
|
{
|
|
3812
3870
|
description: "Enable DPoP requirement",
|
|
3813
3871
|
command: "geonic admin api-keys update <key-id> --dpop-required"
|