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