github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/docs/permissions.md (about) 1 [Table of contents](README.md#table-of-contents) 2 3 # Permissions 4 5 ## When the permissions are used? 6 7 The permissions are used when a request is made to cozy stack. It allows to let 8 the owner of the cozy instance controls the access to her data, files and 9 actions on them. The permissions are given in several contexts. Let's see them! 10 11 ### Client-side apps 12 13 When the user installs a new client-side app, she is asked to accept an initial 14 set of permissions for this app. This set of permissions is described in the 15 manifest of the app. 16 17 Later, the application can gain more permissions via the [intents](intents.md) 18 and optional permissions. See below for more details. 19 20 When the authentified user access a client-side app, the app receives a token 21 from the stack that can be used in later requests to the stack as a proof of the 22 permissions it owns. 23 24 ### External apps via OAuth2 25 26 An external application can ask for permissions via the OAuth2 dance, and use 27 them later with the access token. The permissions are in the `scope` parameter. 28 29 ### Sharing with other users 30 31 The owner of a cozy instance can share some documents and files with other 32 users. It can be done in two ways: 33 34 - If the other user also has a cozy, it can be a cozy-to-cozy sharing. 35 - Else, the owner can give to him a link with a code or a shortcode. 36 37 ## What is a permission? 38 39 A permission gives the right for a request having it to do something on the 40 stack. It is defined by four components. 41 42 ### Type 43 44 `type` is the attribute used in JSON-API or the `doctype` for the Data System. 45 46 It is the only mandatory component. If just the `type` is specified, it gives 47 access to all the operations on this `type`. For example, a permission on type 48 `io.cozy.contacts` gives the right to create, read, update and delete any 49 contact, and to fetch all the contacts. A permission on type `io.cozy.files` 50 allow to access and modify any file or directory. 51 52 Some known types: 53 54 - `io.cozy.files`, for files and folder in the [VFS](files.md) 55 - `io.cozy.apps`, for [apps](apps.md) 56 - `io.cozy.settings`, for the [settings](settings.md) 57 - `io.cozy.jobs` and `io.cozy.triggers`, for [jobs](jobs.md) 58 - `io.cozy.oauth.clients`, to list and revoke [OAuth 2 clients](auth.md) 59 60 It is also possible to use a wildcard to use a doctype and its sub-doctypes if 61 the doctype contains at least 3 `.`. 62 For example, `io.cozy.bank.*` will give access to `io.cozy.bank`, 63 `io.cozy.bank.accounts`, `io.cozy.bank.accounts.stats`, 64 `io.cozy.bank.settings`, etc. `io.cozy.*` will give you an error. 65 66 ### Verbs 67 68 It says which HTTP verbs can be used for requests to the cozy-stack. `GET` will 69 give read-only access, `DELETE` can be used for deletions, etc. Verbs should be 70 declared in a list, like `["GET", "POST", "DELETE"]`, and use `["ALL"]` as a 71 shortcut for `["GET", "POST", "PUT", "PATCH", "DELETE"]` (it is the default). 72 73 **Note**: `HEAD` is implicitely implied when `GET` is allowed. `OPTIONS` for 74 Cross-Origin Resources Sharing is always allowed, the stack does not have the 75 informations about the permission when it answers the request. 76 77 ### Values 78 79 It's possible to restrict the permissions to only some documents of a doctype, 80 or to just some files and folders. You can give a list of ids in `values`. 81 82 **Note**: a permission for a folder also gives permissions with same verbs for 83 files and folders inside it. 84 85 ### Selector 86 87 By default, the `values` are checked with the `id`. But it's possible to use a 88 `selector` to filter on another `field`. In particular, it can be used for 89 sharing. A user may share a calendar and all the events inside it. It will be 90 done with two permissions. The first one is for the calendar: 91 92 ```json 93 { 94 "type": "io.cozy.calendars", 95 "verbs": ["GET"], 96 "values": ["1355812c-d41e-11e6-8467-53be4648e3ad"] 97 } 98 ``` 99 100 And the other is for the events inside the calendar: 101 102 ```json 103 { 104 "type": "io.cozy.events", 105 "verbs": ["GET"], 106 "selector": "calendar-id", 107 "values": ["1355812c-d41e-11e6-8467-53be4648e3ad"] 108 } 109 ``` 110 111 ## What format for a permission? 112 113 ### JSON 114 115 The prefered format for permissions is JSON. Each permission is a map with the 116 `type`, `verbs`, `values` and `selector` see above, plus a `description` that 117 can be used to give more informations to the user. Only the `type` field is 118 mandatory. 119 120 In the manifest, the permissions are regrouped in a map. The key is not very 121 relevant, it's just here for localization. The same key is used in the `locales` 122 field to identify the permission. 123 124 Example: 125 126 ```json 127 { 128 "permissions": { 129 "contacts": { 130 "description": "Required for autocompletion on @name", 131 "type": "io.cozy.contacts", 132 "verbs": ["GET"] 133 }, 134 "images": { 135 "description": "Required for the background", 136 "type": "io.cozy.files", 137 "verbs": ["GET", "POST"], 138 "values": ["io.cozy.files.music-dir"] 139 }, 140 "mail": { 141 "description": "Required to send a congratulations email to your friends", 142 "type": "io.cozy.jobs", 143 "selector": "worker", 144 "values": ["sendmail"] 145 } 146 } 147 } 148 ``` 149 150 ### Inline 151 152 OAuth2 as a `scope` parameter for defining the permissions given to the 153 application. But it's only a string, not a JSON. In that case, we use a space 154 delimited list of permissions, each permission is written compactly with `:` 155 between the components. 156 157 Example: 158 159 ``` 160 io.cozy.contacts io.cozy.files:GET:io.cozy.files.music-dir io.cozy.jobs:POST:sendmail:worker 161 ``` 162 163 **Note**: the `verbs` component can't be omitted when the `values` and 164 `selector` are used. 165 166 ### Inspiration 167 168 - [Access control on other similar platforms](https://news.ycombinator.com/item?id=12784999) 169 170 ## Routes 171 172 ### GET /permissions/self 173 174 List the permissions for a given token 175 176 #### Request 177 178 ```http 179 GET /permissions/self HTTP/1.1 180 Host: cozy.example.net 181 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 182 Accept: application/vnd.api+json 183 ``` 184 185 #### Response 186 187 ```http 188 HTTP/1.1 200 OK 189 Content-Type: application/vnd.api+json 190 ``` 191 192 ```json 193 { 194 "data": { 195 "type": "io.cozy.permissions", 196 "id": "5a9c1844-d427-11e6-ab36-2b684d437b0d", 197 "attributes": { 198 "type": "app", 199 "source_id": "io.cozy.apps/my-awesome-game", 200 "permissions": { 201 "contacts": { 202 "description": "Required for autocompletion on @name", 203 "type": "io.cozy.contacts", 204 "verbs": ["GET"] 205 }, 206 "images": { 207 "description": "Required for the background", 208 "type": "io.cozy.files", 209 "verbs": ["GET"], 210 "values": ["io.cozy.files.music-dir"] 211 }, 212 "mail": { 213 "description": "Required to send a congratulations email to your friends", 214 "type": "io.cozy.jobs", 215 "selector": "worker", 216 "values": ["sendmail"] 217 } 218 } 219 } 220 } 221 } 222 ``` 223 224 #### Special case 225 226 The token can be a sharecode when a member of a sharing is previewing a 227 sharing. When it is the case, the member information from the sharing is 228 included in the response, like this: 229 230 ```json 231 { 232 "data": { 233 "type": "io.cozy.permissions", 234 "id": "bf716babb70b73b89c870fccce00233f", 235 "attributes": { 236 "type": "share-preview", 237 "source_id": "io.cozy.sharings/bf716babb70b73b89c870fccce00233a", 238 "permissions": { 239 "Essai": { 240 "type": "io.cozy.files", 241 "verbs": ["GET"], 242 "values": ["c2930bef3705096d63f5c8fb60019cc0"] 243 } 244 }, 245 "cozyMetadata": { 246 "doctypeVersion": "", 247 "metadataVersion": 1, 248 "createdAt": "2020-10-19T16:12:31.440253797+02:00", 249 "createdByApp": "drive", 250 "updatedAt": "2020-10-19T16:12:31.440253797+02:00" 251 } 252 }, 253 "meta": { 254 "rev": "1-18c3bc158cf5039f60fefe5fc2fcad67" 255 }, 256 "links": { 257 "self": "/permissions/bf716babb70b73b89c870fccce00233f", 258 "related": "/sharings/bf716babb70b73b89c870fccce00233a" 259 } 260 }, 261 "included": [ 262 { 263 "type": "io.cozy.sharings.members", 264 "attributes": { 265 "status": "seen", 266 "name": "Bob", 267 "email": "bob@cozy.localhost" 268 } 269 } 270 ] 271 } 272 ``` 273 274 ### POST /permissions 275 276 Create a new set of permissions. It can also associates one or more codes to it, 277 via the `codes` parameter in the query string. These codes can then be sent to 278 other people as a way to give these permissions (sharing by links). For each 279 `code` created, a corresponding `shortcode` is generated and can be used to 280 shorten links for sharing. The `codes` parameter is a comma separed list of 281 values. The role of these values is to identify the codes if you want to revoke 282 some of them later. A `ttl` parameter can also be given to make the codes 283 expires after a delay ([bigduration 284 format](https://github.com/justincampbell/bigduration/blob/master/README.md)). 285 286 If the `ttl` does not exceed 1 hour, it is possible to add a `tinycode=true` 287 parameter to the query-string to have a shortcode of 6 digits. 288 289 **Note**: it is only possible to create a strict subset of the permissions 290 associated to the sent token. 291 292 #### Request 293 294 ```http 295 POST /permissions?codes=bob,jane&ttl=1D HTTP/1.1 296 Host: cozy.example.net 297 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 298 Content-Type: application/vnd.api+json 299 Accept: application/vnd.api+json 300 ``` 301 302 ```json 303 { 304 "data": { 305 "type": "io.cozy.permissions", 306 "attributes": { 307 "source_id": "io.cozy.apps/my-awesome-game", 308 "password": "HelloWorld!", 309 "permissions": { 310 "images": { 311 "type": "io.cozy.files", 312 "verbs": ["GET"], 313 "values": ["io.cozy.files.music-dir"] 314 } 315 } 316 } 317 } 318 } 319 ``` 320 321 #### Response 322 323 ```http 324 HTTP/1.1 200 OK 325 Content-Type: application/vnd.api+json 326 ``` 327 328 ```json 329 { 330 "data": { 331 "id": "a340d5e0-d647-11e6-b66c-5fc9ce1e17c6", 332 "type": "io.cozy.permissions", 333 "attributes": { 334 "type": "share", 335 "source_id": "io.cozy.apps/my-awesome-game", 336 "codes": { 337 "bob": "yuot7NaiaeGugh8T", 338 "jane": "Yohyoo8BHahh1lie" 339 }, 340 "shortcodes": { 341 "bob": "abcdeFGHIJ01", 342 "jane": "123456aBCdef" 343 }, 344 "expires_at": 1483951978, 345 "password": true, 346 "permissions": { 347 "images": { 348 "type": "io.cozy.files", 349 "verbs": ["GET"], 350 "values": ["io.cozy.files.music-dir"] 351 } 352 } 353 } 354 } 355 } 356 ``` 357 358 ### GET /permissions/:id 359 360 Return the informations about a set of permissions 361 362 #### Request 363 364 ```http 365 GET /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP/1.1 366 Host: cozy.example.net 367 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 368 Accept: application/vnd.api+json 369 ``` 370 371 #### Response 372 373 ```http 374 HTTP/1.1 200 OK 375 Content-Type: application/vnd.api+json 376 ``` 377 378 ```json 379 { 380 "data": { 381 "id": "a340d5e0-d647-11e6-b66c-5fc9ce1e17c6", 382 "type": "io.cozy.permissions", 383 "attributes": { 384 "type": "share", 385 "source_id": "io.cozy.apps/my-awesome-game", 386 "codes": { 387 "bob": "yuot7NaiaeGugh8T", 388 "jane": "Yohyoo8BHahh1lie" 389 }, 390 "shortcodes": { 391 "bob": "abcdeFGHIJ01", 392 "jane": "123456aBCdef" 393 }, 394 "expires_at": 1483951978, 395 "password": true, 396 "permissions": { 397 "images": { 398 "type": "io.cozy.files", 399 "verbs": ["GET"], 400 "values": ["io.cozy.files.music-dir"] 401 } 402 } 403 } 404 } 405 } 406 ``` 407 408 ### PATCH /permissions/:id 409 410 Add permissions in this permissions set. It can be used in inter-apps context as 411 a way to give another app the permission for some data. For example, the contact 412 application can send a "_pick a photo_" intent to the photos application with 413 its permission id, and the photos app can then let the user choose a photo and 414 give the contacts application the permissions to use it. 415 416 This route also accepts a [document metadata](https://github.com/cozy/cozy-doctypes/#document-metadata) to update document informations. 417 418 #### Request to add / remove codes with a document metadata 419 420 ```http 421 PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP/1.1 422 Host: cozy.example.net 423 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 424 Content-Type: application/vnd.api+json 425 Accept: application/vnd.api+json 426 ``` 427 428 ```json 429 { 430 "data": { 431 "id": "a340d5e0-d647-11e6-b66c-5fc9ce1e17c6", 432 "type": "io.cozy.permissions", 433 "attributes": { 434 "codes": { 435 "jane": "Yohyoo8BHahh1lie" 436 } 437 }, 438 "cozyMetadata": { 439 "doctypeVersion": 1, 440 "metadataVersion": 1, 441 "updatedAt": "2019-05-14T12:00:37.372193145+02:00" 442 } 443 } 444 } 445 ``` 446 447 #### Request to add permissions 448 449 ```http 450 PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP/1.1 451 Host: cozy.example.net 452 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 453 Content-Type: application/vnd.api+json 454 Accept: application/vnd.api+json 455 ``` 456 457 ```json 458 { 459 "data": { 460 "attributes": { 461 "id": "a340d5e0-d647-11e6-b66c-5fc9ce1e17c6", 462 "type": "io.cozy.permissions", 463 "permissions": { 464 "add-this": { 465 "type": "io.cozy.files", 466 "verbs": ["GET"], 467 "values": ["some-picture-id"] 468 } 469 } 470 } 471 } 472 } 473 ``` 474 475 #### Request to remove permissions 476 477 ```http 478 PATCH /permissions/a340d5e0-d647-11e6-b66c-5fc9ce1e17c6 HTTP/1.1 479 Host: cozy.example.net 480 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 481 Content-Type: application/vnd.api+json 482 Accept: application/vnd.api+json 483 ``` 484 485 ```json 486 { 487 "data": { 488 "attributes": { 489 "id": "a340d5e0-d647-11e6-b66c-5fc9ce1e17c6", 490 "type": "io.cozy.permissions", 491 "permissions": { 492 "remove-this": {} 493 } 494 } 495 } 496 } 497 ``` 498 499 #### Reponse 500 501 ```http 502 HTTP/1.1 200 OK 503 Content-Type: application/vnd.api+json 504 ``` 505 506 ```json 507 { 508 "data": { 509 "id": "a340d5e0-d647-11e6-b66c-5fc9ce1e17c6", 510 "type": "io.cozy.permissions", 511 "attributes": { 512 "type": "share", 513 "source_id": "io.cozy.apps/my-awesome-game", 514 "codes": { 515 "bob": "yuot7NaiaeGugh8T" 516 }, 517 "shortcodes": { 518 "bob": "abcdeFGHIJ01" 519 }, 520 "expires_at": 1483951978, 521 "permissions": { 522 "images": { 523 "type": "io.cozy.files", 524 "verbs": ["GET"], 525 "values": ["io.cozy.files.music-dir"] 526 } 527 } 528 } 529 } 530 } 531 ``` 532 533 ### DELETE /permissions/:id 534 535 Delete a set of permissions. For example, some permissions were used by a user 536 to share a photo album with her friends, and then she changed her mind and 537 cancel the sharing. 538 539 #### Request 540 541 ```http 542 DELETE /permissions/fa11561c-d645-11e6-83df-cbf577804d55 HTTP/1.1 543 Host: cozy.example.net 544 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 545 ``` 546 547 #### Reponse 548 549 ```http 550 HTTP/1.1 204 No Content 551 ``` 552 553 ### POST /permissions/exists 554 555 List permissions for some documents 556 557 #### Request 558 559 ```http 560 POST /permissions/exists HTTP/1.1 561 Host: cozy.example.net 562 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 563 Content-Type: application/vnd.api+json 564 Accept: application/vnd.api+json 565 ``` 566 567 ```json 568 { 569 "data": [ 570 { "type": "io.cozy.files", "id": "94375086-e2e2-11e6-81b9-5bc0b9dd4aa4" }, 571 { "type": "io.cozy.files", "id": "4cfbd8be-8968-11e6-9708-ef55b7c20863" }, 572 { "type": "io.cozy.files", "id": "a340d5e0-d647-11e6-b66c-5fc9ce1e17c6" }, 573 { "type": "io.cozy.files", "id": "94375086-e2e2-11e6-81b9-5bc0b9dd4aa4" } 574 ] 575 } 576 ``` 577 578 #### Reponse 579 580 ```http 581 HTTP/1.1 200 OK 582 Content-Type: application/vnd.api+json 583 ``` 584 585 ```json 586 { 587 "data": [ 588 { "type": "io.cozy.files", "id": "94375086-e2e2-11e6-81b9-5bc0b9dd4aa4", 589 "verbs":["GET"] }, 590 { "type": "io.cozy.files", "id": "a340d5e0-d647-11e6-b66c-5fc9ce1e17c6", 591 "verbs":["GET", "POST"] } 592 ] 593 } 594 ``` 595 596 ### PATCH /permissions/apps/:slug 597 598 Add permissions or remove permissions to the web application with specified 599 slug. It behaves like the `PATCH /permissions/:id` route. See this route for 600 more examples. 601 602 ### PATCH /permissions/konnectors/:slug 603 604 Add permissions or remove permissions to the konnector with specified slug. It 605 behaves like the `PATCH /permissions/:id` route. See this route for more 606 examples. 607 608 ### GET /permissions/doctype/:doctype/shared-by-link 609 610 List permissions for a doctype that are used for a "share by links". This 611 endpoint is paginated, with a default number of 30 items per page, and a limit 612 of 100 items per page. 613 614 #### Request 615 616 ```http 617 GET /permissions/doctype/io.cozy.events/shared-by-link HTTP/1.1 618 Host: cozy.example.net 619 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 620 Content-Type: application/vnd.api+json 621 Accept: application/vnd.api+json 622 ``` 623 624 #### Reponse 625 626 ```http 627 HTTP/1.1 200 OK 628 Content-Type: application/vnd.api+json 629 ``` 630 631 ```json 632 { 633 "data": [ 634 { 635 "type": "io.cozy.permissions", 636 "id": "c47f82396d09bfcd270343c5855b30a0", 637 "attributes": { 638 "type": "share", 639 "permissions": { 640 "rule0": { 641 "type": "io.cozy.events", 642 "verbs": ["PATCH", "DELETE"], 643 "values": ["c47f82396d09bfcd270343c5855b0eea"] 644 } 645 }, 646 "codes": { 647 "bob": "secret" 648 }, 649 "shortcodes": { 650 "bob": "abcdeFGHIJ01" 651 } 652 }, 653 "meta": { "rev": "1-d46b6358683b80c8d59fc55d6de54127" }, 654 "links": { "self": "/permissions/c47f82396d09bfcd270343c5855b30a0" } 655 }, 656 { 657 "type": "io.cozy.permissions", 658 "id": "c47f82396d09bfcd270343c5855b351a", 659 "attributes": { 660 "type": "share", 661 "permissions": { 662 "rule0": { 663 "type": "io.cozy.events", 664 "verbs": ["GET"], 665 "values": ["c47f82396d09bfcd270343c5855b169b"] 666 } 667 }, 668 "codes": { 669 "bob": "secret" 670 }, 671 "shortcodes": { 672 "bob": "abcdeFGHIJ01" 673 } 674 }, 675 "meta": { "rev": "1-920af658575a56e9e84685f1b09e5c23" }, 676 "links": { "self": "/permissions/c47f82396d09bfcd270343c5855b351a" } 677 } 678 ] 679 } 680 ``` 681 682 Permissions required: GET on the whole doctype