@geolonia/geonicdb-cli 0.6.3 → 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 +77 -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,8 +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
|
];
|
|
951
|
+
var API_KEY_SCOPES_HELP_NOTES = [
|
|
952
|
+
"Valid scopes:",
|
|
953
|
+
" read:entities, write:entities, read:subscriptions, write:subscriptions,",
|
|
954
|
+
" read:registrations, write:registrations"
|
|
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
|
+
}
|
|
950
965
|
function resolveOptions(cmd) {
|
|
951
966
|
const opts = cmd.optsWithGlobals();
|
|
952
967
|
const config = loadConfig(opts.profile);
|
|
@@ -1421,7 +1436,7 @@ function addMeApiKeysSubcommand(me) {
|
|
|
1421
1436
|
command: "geonic me api-keys list"
|
|
1422
1437
|
}
|
|
1423
1438
|
]);
|
|
1424
|
-
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(
|
|
1425
1440
|
withErrorHandler(async (json, _opts, cmd) => {
|
|
1426
1441
|
const opts = cmd.opts();
|
|
1427
1442
|
if (opts.origins !== void 0) {
|
|
@@ -1434,13 +1449,14 @@ function addMeApiKeysSubcommand(me) {
|
|
|
1434
1449
|
let body;
|
|
1435
1450
|
if (json) {
|
|
1436
1451
|
body = await parseJsonInput(json);
|
|
1437
|
-
} 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) {
|
|
1438
1453
|
const payload = {};
|
|
1439
1454
|
if (opts.name) payload.name = opts.name;
|
|
1440
1455
|
if (opts.scopes) payload.allowedScopes = opts.scopes.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1441
1456
|
if (opts.origins) payload.allowedOrigins = opts.origins.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1442
1457
|
if (opts.entityTypes) payload.allowedEntityTypes = opts.entityTypes.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1443
1458
|
if (opts.dpopRequired !== void 0) payload.dpopRequired = opts.dpopRequired;
|
|
1459
|
+
if (opts.permissions) payload.permissions = parsePermissions(opts.permissions);
|
|
1444
1460
|
if (opts.rateLimit) {
|
|
1445
1461
|
const raw = opts.rateLimit.trim();
|
|
1446
1462
|
if (!/^\d+$/.test(raw)) {
|
|
@@ -1489,12 +1505,22 @@ function addMeApiKeysSubcommand(me) {
|
|
|
1489
1505
|
console.error("API key created.");
|
|
1490
1506
|
})
|
|
1491
1507
|
);
|
|
1492
|
-
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
|
+
]);
|
|
1493
1515
|
addExamples(create, [
|
|
1494
1516
|
{
|
|
1495
1517
|
description: "Create an API key with flags",
|
|
1496
1518
|
command: "geonic me api-keys create --name my-app --scopes read:entities --origins 'https://example.com'"
|
|
1497
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
|
+
},
|
|
1498
1524
|
{
|
|
1499
1525
|
description: "Create and save API key to config",
|
|
1500
1526
|
command: "geonic me api-keys create --name my-app --save"
|
|
@@ -3196,7 +3222,7 @@ function registerUsersCommand(parent) {
|
|
|
3196
3222
|
}
|
|
3197
3223
|
]);
|
|
3198
3224
|
const create = users.command("create [json]").description(
|
|
3199
|
-
'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.'
|
|
3200
3226
|
).action(
|
|
3201
3227
|
withErrorHandler(async (json, _opts, cmd) => {
|
|
3202
3228
|
const body = await parseJsonInput(json);
|
|
@@ -3211,8 +3237,12 @@ function registerUsersCommand(parent) {
|
|
|
3211
3237
|
);
|
|
3212
3238
|
addExamples(create, [
|
|
3213
3239
|
{
|
|
3214
|
-
description: "Create
|
|
3215
|
-
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>"}'`
|
|
3216
3246
|
},
|
|
3217
3247
|
{
|
|
3218
3248
|
description: "Create from a JSON file",
|
|
@@ -3356,7 +3386,7 @@ function registerPoliciesCommand(parent) {
|
|
|
3356
3386
|
}
|
|
3357
3387
|
]);
|
|
3358
3388
|
const create = policies.command("create [json]").description(
|
|
3359
|
-
'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'
|
|
3360
3390
|
).action(
|
|
3361
3391
|
withErrorHandler(async (json, _opts, cmd) => {
|
|
3362
3392
|
const body = await parseJsonInput(json);
|
|
@@ -3374,6 +3404,18 @@ function registerPoliciesCommand(parent) {
|
|
|
3374
3404
|
description: "Create with inline JSON",
|
|
3375
3405
|
command: `geonic admin policies create '{"description":"Allow all entities","rules":[{"ruleId":"allow-all","effect":"Permit"}]}'`
|
|
3376
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
|
+
},
|
|
3377
3419
|
{
|
|
3378
3420
|
description: "Create from a JSON file",
|
|
3379
3421
|
command: "geonic admin policies create @policy.json"
|
|
@@ -3672,6 +3714,7 @@ function buildBodyFromFlags(opts) {
|
|
|
3672
3714
|
payload.rateLimit = { perMinute };
|
|
3673
3715
|
}
|
|
3674
3716
|
if (opts.dpopRequired !== void 0) payload.dpopRequired = opts.dpopRequired;
|
|
3717
|
+
if (opts.permissions) payload.permissions = parsePermissions(opts.permissions);
|
|
3675
3718
|
if (opts.tenantId) payload.tenantId = opts.tenantId;
|
|
3676
3719
|
return payload;
|
|
3677
3720
|
}
|
|
@@ -3717,14 +3760,14 @@ function registerApiKeysCommand(parent) {
|
|
|
3717
3760
|
command: "geonic admin api-keys get <key-id>"
|
|
3718
3761
|
}
|
|
3719
3762
|
]);
|
|
3720
|
-
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(
|
|
3721
3764
|
withErrorHandler(async (json, _opts, cmd) => {
|
|
3722
3765
|
const opts = cmd.opts();
|
|
3723
3766
|
validateOrigins(void 0, opts);
|
|
3724
3767
|
let body;
|
|
3725
3768
|
if (json) {
|
|
3726
3769
|
body = await parseJsonInput(json);
|
|
3727
|
-
} 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) {
|
|
3728
3771
|
body = buildBodyFromFlags(opts);
|
|
3729
3772
|
} else {
|
|
3730
3773
|
body = await parseJsonInput();
|
|
@@ -3756,12 +3799,22 @@ function registerApiKeysCommand(parent) {
|
|
|
3756
3799
|
console.error("API key created.");
|
|
3757
3800
|
})
|
|
3758
3801
|
);
|
|
3759
|
-
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
|
+
]);
|
|
3760
3809
|
addExamples(create, [
|
|
3761
3810
|
{
|
|
3762
3811
|
description: "Create an API key with flags",
|
|
3763
3812
|
command: "geonic admin api-keys create --name my-key --scopes read:entities,write:entities --origins '*'"
|
|
3764
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
|
+
},
|
|
3765
3818
|
{
|
|
3766
3819
|
description: "Create an API key with DPoP required",
|
|
3767
3820
|
command: "geonic admin api-keys create --name my-key --dpop-required"
|
|
@@ -3771,7 +3824,7 @@ function registerApiKeysCommand(parent) {
|
|
|
3771
3824
|
command: "geonic admin api-keys create @key.json --save"
|
|
3772
3825
|
}
|
|
3773
3826
|
]);
|
|
3774
|
-
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(
|
|
3775
3828
|
withErrorHandler(
|
|
3776
3829
|
async (keyId, json, _opts, cmd) => {
|
|
3777
3830
|
const opts = cmd.opts();
|
|
@@ -3779,7 +3832,7 @@ function registerApiKeysCommand(parent) {
|
|
|
3779
3832
|
let body;
|
|
3780
3833
|
if (json) {
|
|
3781
3834
|
body = await parseJsonInput(json);
|
|
3782
|
-
} 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) {
|
|
3783
3836
|
body = buildBodyFromFlags(opts);
|
|
3784
3837
|
} else {
|
|
3785
3838
|
body = await parseJsonInput();
|
|
@@ -3797,12 +3850,22 @@ function registerApiKeysCommand(parent) {
|
|
|
3797
3850
|
}
|
|
3798
3851
|
)
|
|
3799
3852
|
);
|
|
3800
|
-
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
|
+
]);
|
|
3801
3860
|
addExamples(update, [
|
|
3802
3861
|
{
|
|
3803
3862
|
description: "Update an API key name",
|
|
3804
3863
|
command: "geonic admin api-keys update <key-id> --name new-name"
|
|
3805
3864
|
},
|
|
3865
|
+
{
|
|
3866
|
+
description: "Update permissions",
|
|
3867
|
+
command: "geonic admin api-keys update <key-id> --permissions read,write"
|
|
3868
|
+
},
|
|
3806
3869
|
{
|
|
3807
3870
|
description: "Enable DPoP requirement",
|
|
3808
3871
|
command: "geonic admin api-keys update <key-id> --dpop-required"
|