{"_id":"56a0bda13697d80d002ac60d","parentDoc":null,"user":"54774c47f3736008009e9e0c","category":{"_id":"56a0bd9f3697d80d002ac5e9","__v":3,"project":"54774d9af3736008009e9e0e","version":"56a0bd9e3697d80d002ac5e7","pages":["56a0bda13697d80d002ac5ff","56a0bda13697d80d002ac600","56a0bda13697d80d002ac601","56a0bda13697d80d002ac602","56a0bda13697d80d002ac603","56a0bda13697d80d002ac604","56a0bda13697d80d002ac605","56a0bda13697d80d002ac606","56a0bda13697d80d002ac607","56a0bda13697d80d002ac608","56a0bda13697d80d002ac609","56a0bda13697d80d002ac60a","56a0bda13697d80d002ac60b","56a0bda13697d80d002ac60c","56a0bda13697d80d002ac60d","56a0bda13697d80d002ac60e","56a0bda13697d80d002ac60f","56a0bda13697d80d002ac610","56a0bda13697d80d002ac611","56a0bda13697d80d002ac612","56a0bda13697d80d002ac613","56a0bda13697d80d002ac614","56a5d7f7d222d20d00500d91","56a8c90fc48ee00d0092e1d1"],"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-02-05T14:34:09.364Z","from_sync":false,"order":17,"slug":"developer-manual","title":"Advanced Topics"},"project":"54774d9af3736008009e9e0e","version":{"_id":"56a0bd9e3697d80d002ac5e7","project":"54774d9af3736008009e9e0e","__v":20,"createdAt":"2016-01-21T11:14:38.131Z","releaseDate":"2016-01-21T11:14:38.131Z","categories":["56a0bd9f3697d80d002ac5e8","56a0bd9f3697d80d002ac5e9","56a0bd9f3697d80d002ac5ea","56a0bd9f3697d80d002ac5eb","56b098a43a5b810d00745e3f","56b098da8f7a4f0d0029dd10","56d5a8ecf612b80b00fb69cd","570989853ab43c0e0072b2d6","571006aa10300c0e007f6133","5735a52431a73b1700887ca0","5744b0529e045c0e00b7a7a2","5744b1d0b56d431700d8a4fb","5744b1fb55d65a0e00b436e1","5744b218f9c7411700ce560e","5744b220f9c7411700ce560f","5744b2259e045c0e00b7a7a7","5744b22cf8b79f0e00de6a2d","5744b23155d65a0e00b436e4","5744b242c758290e00fbc235","5744b2569e045c0e00b7a7a8","5756a3f2bb92962900dafe3d","57ee23e81e42900e0014a42f","581c822c98676e0f00d240ef"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"Sockets","version_clean":"1.1.0","version":"1.1"},"__v":8,"updates":["57bedf12fd5b9d0e00c55229"],"next":{"pages":[],"description":""},"createdAt":"2016-01-18T13:43:23.019Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":6,"body":"Chapter sections:\n1. [Overview](#overview)\n2. [Permissions](#permissions)\n3. [Permission Types](#permission-types)\n4. [Using API Keys and User Keys](#using-api-keys-and-user-keys)\n5. [Using API Key with allow_anonymous_read flag](#using-api-key-with-allow_anonymous_read-flag)\n6. [Syncano authentication keys](#syncano-authentication-keys)\n7. [Summary](#summary) \n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Overview\"\n}\n[/block]\nThe permissions system was designed so that you can have control over what your application users have access to on Syncano. If you create a file storage app, you'd probably want the users to see their own files and not files of other users. That's exactly what you can achieve by setting up proper permissions.\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Permissions\"\n}\n[/block]\n\nThe permissions system on Syncano is inspired by [UNIX file system permissions](http://en.wikipedia.org/wiki/File_system_permissions).\n\n\nWhen you configure permissions, you configure them for one of three categories: \n* `owner`\n* `group` \n* `other`\n\nThe owner is a category that relates only to Data Objects. When a Data Object is created we can set a User as its `owner`. \nGroups are groups of Users (you can read more about creating groups in [this chapter](groups)). \nOthers will be Users that are not an `owner` and are not assigned to a `group` that is connected with a resource (Data Objects, Data Classes and Channels). While `owner` only applies to Data Objects, `groups` and `other` categories can also be set for Data Classes and Channels.\n\nThe table below should clarify the concept a bit more:\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"`owner`\",\n    \"0-1\": \"`owner_permissions`\",\n    \"1-0\": \"`group`\",\n    \"1-1\": \"`group_permissions`\",\n    \"2-0\": \"`other`\",\n    \"2-1\": \"`other_permissions`\",\n    \"0-2\": \"Data Objects\",\n    \"1-2\": \"Data Objects, Data Classes, Channels\",\n    \"2-2\": \"Data Objects, Data Classes, Channels\",\n    \"h-0\": \"Category\",\n    \"h-1\": \"Property\",\n    \"h-2\": \"Applies to\",\n    \"0-3\": \"The owner's permissions determine what actions the owner of the Data Object can perform on the resource.\",\n    \"1-3\": \"The groups permissions determine what actions a user in the group can perform on a resource.\",\n    \"2-3\": \"The permissions for others indicate what action all other users can perform on the resource.\",\n    \"h-3\": \"Description\"\n  },\n  \"cols\": 4,\n  \"rows\": 3\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Since Account Keys (administrators) and API Keys with ignore_acl set to true can ignore permissions, `other` relates only to users (who will authenticate with API Key and User Key combination).\",\n  \"title\": \"other\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Permission Types\"\n}\n[/block]\nPermission types define the level at which a user can interact with a resource.  They are represented as values that you can set for `owner_permissions`, `group_permissions` and `other_permissions` properties. These values are a bit different for:\n- [Data Objects](#section-permission-types-for-data-objects-)\n- [Data Classes](#section-permission-types-for-classes-)\n- [Channels](#section-permission-types-for-channels-)\n\n## Permission Types for Data Objects:\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"`none`\",\n    \"1-0\": \"`read`\",\n    \"2-0\": \"`write`\",\n    \"3-0\": \"`full`\",\n    \"h-0\": \"Permission Type\",\n    \"h-1\": \"Description\",\n    \"1-1\": \"Grants the capability to read the Data Object.\",\n    \"2-1\": \"Grants the capability to read and write the Data Object.\",\n    \"3-1\": \"Grants read/write permissions plus the possibility of deleting the Data Object.\",\n    \"0-1\": \"Default mode where users don't have access to the Data Object.\"\n  },\n  \"cols\": 2,\n  \"rows\": 4\n}\n[/block]\n### Examples\n\nIf you never dealt with UNIX file system permissions, the concept might be a bit vague at first. We'll try to explain with a couple of examples. Let's consider 3 scenarios, when a User with an `id` = 123 will be able to read a Data Object with an `id`=1: \n1. If a User is an `owner` and `owner_permissions` is `read` or higher (`write` or `full`), this is how the Data Object permission properties will look (non-permission properties removed for clarity):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"id\\\": 1, \\n    \\\"owner\\\": 123, \\n    \\\"owner_permissions\\\": \\\"read\\\", \\n    \\\"group\\\": null, \\n    \\\"group_permissions\\\": \\\"none\\\", \\n    \\\"other_permissions\\\": \\\"none\\\"\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n2. If the user belongs to a `group` associated with that Data Object and that Data Object has `group_permissions` = `read` or higher. \nIf our user belonged to a Group with `id` 321, then this is how the Data Object permission settings could look like:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"id\\\": 1, \\n    \\\"owner\\\": null, \\n    \\\"owner_permissions\\\": \\\"none\\\", \\n    \\\"group\\\": 321, \\n    \\\"group_permissions\\\": \\\"read\\\", \\n    \\\"other_permissions\\\": \\\"none\\\"\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n3. Last check is `other_permissions`. Our user with an id = `123` is not an owner of the Data Object and doesn't belong to a group that is connected with this Data Object. Nevertheless the user can still read the Data Object because `other_permissions` are set to `read`:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"id\\\": 1, \\n    \\\"owner\\\": null, \\n    \\\"owner_permissions\\\": \\\"none\\\", \\n    \\\"group\\\": null, \\n    \\\"group_permissions\\\": \\\"none\\\", \\n    \\\"other_permissions\\\": \\\"read\\\"\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"If a Data Object has `other_permissions` = `full`, it overrides all other permissions completely. So even if a user is not an `owner` and not in a  `group` connected with the Data Object, the user will still have access to a Data Object where `other_permissions` = `full`. Same rule applies to Data Classes and Channels.\"\n}\n[/block]\n ### Creating a Data Object with an `owner_permissions` example\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"To see full guide on adding Data Objects, please see [this chapter](doc:data-objects) of Developer Manual.\"\n}\n[/block]\nIt's worth noting that when a Data Object is created, its `owner_permissions` are `none` by default. What it means is that even if your user creates a Data Object, the user won't have access to it.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/3aQEz5rQ4eTw8mHDi8Kc_Add_data_object_01.png\",\n        \"Add_data_object_01.png\",\n        \"1679\",\n        \"872\",\n        \"#264472\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/8173iRWPSoCg5Zmi2zXw_Add_data_object_02.png\",\n        \"Add_data_object_02.png\",\n        \"1679\",\n        \"873\",\n        \"#849cb4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nTo make sure the user has access you should set the `owner_permissions` to `read` or higher during Data Object creation:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/2xi5jtkQOyGBmswATBAX_Add_data_object_03.png\",\n        \"Add_data_object_03.png\",\n        \"1679\",\n        \"872\",\n        \"#6c84a4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nSame rules apply when you create Data Objects in code: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: API_KEY\\\" \\\\\\n-H \\\"X-USER-KEY: USER_KEY\\\" \\\\\\n-H \\\"Content-type: application/json\\\" \\\\\\n-d '{\\\"data\\\": \\\"I am sample data\\\",\\\"owner_permissions\\\":\\\"read\\\"}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/<INSTANCE>/classes/<DATA_CLASS>/objects/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"from syncano.models import User\\nimport syncano\\n\\nsyncano.connect(api_key=\\\"API_KEY\\\") \\n\\ndata_object = Object.please.create(\\n    instane_name=\\\"INSTANCE_NAME\\\",\\n  \\tclass_name=\\\"CLASS_NAME\\\",\\n    owner_permissions='read',\\n)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require('syncano'); //CommonJS\\nvar instance = new Syncano({\\n  apiKey: API_KEY, \\n  instance: INSTANCE_NAME,\\n  userKey: USER_KEY\\n});\\n\\nvar obj = {\\\"data\\\": \\\"I am sample data\\\",\\\"owner_permissions\\\":\\\"read\\\"};\\n\\ninstance.class('CLASS_NAME').dataobject(obj, callback());\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"ExampleObject obj = new ExampleObject();\\nobj.setOwnerPermissions(DataObjectPermissions.READ);\\nobj.data = \\\"I am sample data\\\";\\nResponse<ExampleObject> response = obj.save();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"// Coming soon!\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// Coming soon!\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"ExampleObject exampleObject = new ExampleObject();\\nexampleObject.OwnerPermissions = DataObjectPermissions.READ;\\nexampleObject.data = \\\"SOME_DATA\\\";\\n\\nsyncano.Please().Save(exampleObject, OnSuccess, OnFailure);\",\n      \"language\": \"text\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\n## Permission Types for Data Classes:\nPermission types for Data Classes are different from the ones for Data Objects, because they not only consider access to a Data Class itself but also to the Data Objects that belong to that Data Class. So if you would like a user to have `read` access to a certain Data Object, you should not only grant that user access to that Data Object but also set its Data Class permissions to `read`.  If you would like your users to be able to create Data Objects within a Data Class, the Data Class should have `create_objects` permission type set for those users (for a group users belongs to, or for `others` - which will affect every other user inside your Syncano Instance).\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"`none`\",\n    \"1-0\": \"`read`\",\n    \"2-0\": \"`create_objects`\",\n    \"h-0\": \"Permission Type\",\n    \"h-1\": \"Description\",\n    \"0-1\": \"Users don't have access to a Data Class and they won't be able to create Data Objects with this Data Class schema.\",\n    \"1-1\": \"Means that users can get Data Class info + read Data Objects associated with that Data Class (provided that Data Objects permissions are set for read or higher for the specific user).\",\n    \"2-1\": \"Default state. Users can read and create Data Objects within that Data Class.\"\n  },\n  \"cols\": 2,\n  \"rows\": 3\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"When a Data Class is being created it's `group_permissions` and `other_permissions` will be `create_objects` by default. This way your application users will have an ability to create Data Objects in all of the Data Classes within an Instance. If you'd like to limit their access you can change the Data Class permissions to `read` or `none`.\"\n}\n[/block]\n### Example\n\nWe'll go through granting users permission to create Data Objects within a Data Class. \nWe'll create a simple Data Class, with only one field (\"title\") that has `other_permissions` = `create_objects`. This way any user will be able to add and read Data Objects within this Data Class.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/91bc042-add_class_permisions.png\",\n        \"add_class_permisions.png\",\n        1938,\n        1530,\n        \"#f7f7f7\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"Content-type: application/json\\\" \\\\\\n-H \\\"X-API-KEY: ACCOUNT_KEY\\\" \\\\\\n-d '{\\\"name\\\": <data_class_name>,\\n     \\\"other_permissions\\\":\\\"create_objects\\\",\\n     \\\"schema\\\":[{\\\"type\\\":\\\"string\\\",\\\"name\\\":\\\"title\\\"}]}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/<instance>/classes/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import python\\nfrom syncano.models import Class\\n\\nsyncano.connect(api_key=\\\"API_KEY\\\")\\n\\nClass.please.create(\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    name=\\\"CLASS_NAME\\\",\\n    other_permissions=\\\"create_objects\\\",\\n    schema=[{'name':'title','type':'string'}]\\n)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require('syncano'); //CommonJS\\nvar account = new Syncano({accountKey: ACCOUNT_KEY});\\n\\nvar options = {\\n  \\\"name\\\": CLASS_NAME,\\n  \\\"other_permissions\\\":\\\"create_objects\\\",\\n  \\\"schema\\\":[{\\\"type\\\":\\\"string\\\",\\\"name\\\":\\\"title\\\"}]\\n};\\n\\naccount.instance('INSTANCE_NAME').class().add(options, callback());\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"SyncanoClass syncanoClass = new SyncanoClass(ExampleObject.class);\\nsyncanoClass.setOtherPermissions(SyncanoClassPermissions.CREATE_OBJECTS);\\n\\nResponse<SyncanoClass> response = syncano.createSyncanoClass(syncanoClass).send();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"// Not supported in iOS Library - please use our Dashboard instead\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// Not supported in iOS Library - please use our Dashboard instead\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    }\n  ]\n}\n[/block]\nAnd that's it! Now any user can create and read objects in this data class. If you'd like to create more fine-grained permissions, you could create a group and add selected users to it. Next, when creating a Data Class, you'd set `group_permissions` to `create_objects` and pass a group id to the `group` parameter:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/qvIeD7raRoCveb9q3L46_Add_class_04.png\",\n        \"Add_class_04.png\",\n        \"1678\",\n        \"871\",\n        \"#274470\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"Content-type: application/json\\\" \\\\\\n-H \\\"X-API-KEY: ACCOUNT_KEY\\\" \\\\\\n-d '{\\\"name\\\": <data_class_name>,\\n     \\\"group_permissions\\\":\\\"create_objects\\\",\\n     \\\"group\\\": group_id,\\n     \\\"schema\\\":[{\\\"type\\\":\\\"string\\\",\\\"name\\\":\\\"title\\\"}]}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/instance/classes/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import python\\nfrom syncano.models.base import Class\\n\\nsyncano.connect(api_key=\\\"API_KEY\\\")\\n\\nClass.please.create(\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    name=\\\"CLASS_NAME\\\",\\n    group_permissions=\\\"create_objects\\\",\\n    group=1,\\n    schema=[{'name':'newer','type':'string'}]\\n)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require('syncano'); //CommonJS\\nvar account = new Syncano({accountKey: ACCOUNT_KEY});\\n\\nvar options = {\\n  \\\"name\\\": CLASS_NAME,\\n  \\\"group_permissions\\\":\\\"create_objects\\\",\\n  \\\"group\\\": GROUP_ID,\\n  \\\"schema\\\":[{\\\"type\\\":\\\"string\\\",\\\"name\\\":\\\"title\\\"}]\\n};\\n\\naccount.instance('INSTANCE_NAME').class().add(options, callback());\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"SyncanoClass syncanoClass = new SyncanoClass(ExampleObject.class);\\nsyncanoClass.setGroup(group.getId());\\nsyncanoClass.setGroupPermissions(SyncanoClassPermissions.CREATE_OBJECTS);\\n\\nResponse<SyncanoClass> response = syncano.createSyncanoClass(syncanoClass).send();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"// Not supported in iOS Library - please use our Dashboard instead\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// Not supported in iOS Library - please use our Dashboard instead\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    }\n  ]\n}\n[/block]\n## Permission Types for Channels:\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Permission Type\",\n    \"h-1\": \"Description\",\n    \"0-0\": \"`none`\",\n    \"1-0\": \"`subscribe`\",\n    \"2-0\": \"`publish`\",\n    \"0-1\": \"Default mode where users don't have access to channel notifications.\",\n    \"1-1\": \"User can receive notifications from a channel.\",\n    \"2-1\": \"User can publish data to a channel.\"\n  },\n  \"cols\": 2,\n  \"rows\": 3\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Channels and their permissions are described in depth in the [Realtime Communication](realtime-communication) chapter of this manual.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Using API Keys and User Keys\"\n}\n[/block]\nCreating API Keys was described in our [Getting Started section](getting-started-with-syncano#getting-an-api-key) and you can read a bit more about User Keys in the [User management chapter](user-management#user-authentication). When it comes to permissions, it is important to know that there are two flags that can be set when creating an API Key:\n* `allow_user_create` - API Key with this flag set to `true` works on the instances/<instance>/users/ endpoint and enables user creation (you can read about adding new users [here](user-management#adding-a-user)).\n* `ignore_acl` - API Key with this flag set to `true` will ignore access control list. What this means is that it will ignore any permissions set for the resources in Syncano. \n* [`allow_anonymous_usage`](#using-api-key-with-allow_anonymous_read-flag) - When set to `true`, API Key with `allow_anonymous_read` will allow making GET requests to Data Classes and Data Objects based on appropriate permissions.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"ignore_acl\",\n  \"body\": \"For example a User that will use a combination of a User Key and an API Key with `ignore_acl` = true will be able to view all Data Objects in a Data Class where normally permissions would prohibit that user to have read access. The user could also create Data Objects in a Data Class where this Data Class doesn't have permission type `create_objects` etc. So, for instance, `ignore_acl` API Keys might be useful if you'd like to have Admin/Moderator Users. You should be careful though because such users would have large control within an instance along with the ability to create/delete Data Classes.\"\n}\n[/block]\nDepending on what you'd like to achieve in your app, you can either use an API Key or a combination of an API Key and a User Key. \n\n## Using an API Key\nAn API Key without `ignore_acl` or `create_user` flags has a rather limited access and mostly can only be used to read data from different endpoints. \n\nThis is how specific API Key permissions per endpoint look like (endpoints that API Key doesn't have permission to view were omitted):\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Endpoint\",\n    \"h-1\": \"Permission\",\n    \"0-0\": \"/instances/\",\n    \"1-0\": \"/api_keys/\",\n    \"2-0\": \"/user/auth/\",\n    \"3-0\": \"/users/\",\n    \"4-0\": \"/groups/\",\n    \"5-0\": \"/classes/\",\n    \"6-0\": \"/classes/<class>/objects/\",\n    \"7-0\": \"/channels/\",\n    \"8-0\": \"/channels/<id>/publish/\",\n    \"9-0\": \"/channels/<id>/history/\",\n    \"9-1\": \"`read`\",\n    \"8-1\": \"`write`\",\n    \"7-1\": \"`read`\",\n    \"6-1\": \"`create`\",\n    \"5-1\": \"`read`\",\n    \"4-1\": \"`read`\",\n    \"3-1\": \"\",\n    \"1-1\": \"`read`\",\n    \"0-1\": \"`read`\",\n    \"0-2\": \"Can view only the instance that the API Key belongs to.\",\n    \"1-2\": \"Can view only own API Key (use account_key or the Syncano Dashboard to view full list of API Keys)\",\n    \"3-2\": \"No read permission - not possible to list all the users. It's possible to add new users when API Key has `allow_user_create` = true.\",\n    \"5-2\": \"Can view data classes when data class permission types are set to `read` or `create_objects`.\",\n    \"6-2\": \"- Can create new objects inside a data class when the data class has `create_objects` permission set. \\n- Can read/write/update/delete objects depending on specific Data Object owner/group/other permissions + also requires data class permission types to be `read` or `create_objects`.\",\n    \"7-2\": \"Can view channels if channel permission types are set to `subscribe` or `publish`.\",\n    \"8-2\": \"Can `write` to a channel if channel permission types are set to `publish`.\",\n    \"9-2\": \"Can `read` a channel if channel permissions are `subscribe` or `publish`.\",\n    \"h-2\": \"Description\",\n    \"2-2\": \"Endpoint where user can POST their user credentials (log in using username and password) and get User Key in response.\",\n    \"4-2\": \"Can view groups.\"\n  },\n  \"cols\": 3,\n  \"rows\": 10\n}\n[/block]\n## Using an API Key + User Key\n\nIn most of the cases your users should be connecting to your app with a combination of User Key and API Key. If that's the case, then some endpoints will behave differently and will be showing data that is scoped for the current user. You'll find a list of these endpoints below:\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"/user/\",\n    \"0-1\": \"`write`\",\n    \"0-2\": \"Endpoint available only with API Key + User Key (Account Key + User Key won't work here!). A User can view only their account details and change their username and/or password.\",\n    \"1-0\": \"/users/\",\n    \"1-2\": \"A User can view only their account details on the list.\",\n    \"1-1\": \"`write`\",\n    \"3-0\": \"/users/<id>/groups/\",\n    \"3-1\": \"`read`\",\n    \"3-2\": \"A User can see only these Groups that he is a part of.\",\n    \"4-1\": \"`read`\",\n    \"4-0\": \"/groups/<id>/users/\",\n    \"4-2\": \"A User can only see themself being a part of a Group.\",\n    \"h-0\": \"Endpoint\",\n    \"h-1\": \"Permission\",\n    \"h-2\": \"Description\",\n    \"2-0\": \"/users/<user_id>/\",\n    \"2-1\": \"`write`\",\n    \"2-2\": \"A User can view their account details and change their username and/or password.\"\n  },\n  \"cols\": 3,\n  \"rows\": 5\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"The Rest of the endpoints will behave in the same manner as if accessed only with an API Key.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Using API Key with allow_anonymous_read flag\"\n}\n[/block]\nWhen set to `true`, API Key with allow_anonymous_read will allow making GET requests to Data Classes and Data Objects *provided that*:\n- Data Objects have `other_permissions` set to `read`, `write` or `full`\n- Data Classes have `other_permissions` set to `read` or `create_objects`\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Please refer to the permissions section [above](#permissions) if you want to learn how to add permissions to Data Classes and Data Objects.\"\n}\n[/block]\nWhat is important here is that this key will have *read* access to all the resources with appropriate permissions without the necessity to pass a User API Key along with it. It might come handy in cases where you'd like some of your apps resources to be accessible without the need for user authentication.\n\n### Adding an API Key with allow_anonymous_read flag\n\nThis is how you can create allow_anonymous_read API Key:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: ACCOUNT_KEY\\\" \\\\\\n-H \\\"Content-type: application/json\\\" \\\\\\n-d '{\\\"allow_anonymous_read\\\": true}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/INSTANCE/api_keys/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import syncano\\nfrom syncano.models import ApiKey\\n\\nsyncano.connect(api_key='API_KEY')\\n\\napi_key = ApiKey.please.create(allow_anonymous_read=True)\\n\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"// Coming soon!\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"// Not supported\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"// Coming soon!\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// Coming soon!\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"// NOT AVAILABLE\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\nResponse (some properties omitted for clarity):\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"allow_anonymous_read\\\": true,\\n    \\\"allow_user_create\\\": false,\\n    \\\"api_key\\\": \\\"cc308b5a686e1ad3e7290717e2b36e11193184d5\\\",\\n    \\\"id\\\": 2581,\\n    \\\"ignore_acl\\\": false\\n}\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"# RAW RESPONSE\\n{\\n  'description': u'', \\n  'links': <syncano.models.fields.LinksWrapper object at 0x7f04094e55d0>,   \\n  'allow_anonymous_read': True, \\n  'allow_user_create': False, \\n  'instance_name': 'INSTANCE_NAME', \\n  'api_key': 'API_KEY', \\n  'id': ID, \\n  'ignore_acl': False\\n}\\n\\n# CODE:\\nprint(api_key.allow_anonymous_read)\\n>> True\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"// Coming soon!\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"// Coming soon!\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// Coming soon!\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Syncano authentication Keys\"\n}\n[/block]\nThe following table shows some of the more commonly used API Endpoints and the specific authentication keys that have the proper permissions to make these calls:\n[block:parameters]\n{\n  \"data\": {\n    \"h-1\": \"API_KEY\",\n    \"h-2\": \"API_KEY & USER_KEY\",\n    \"h-3\": \"ACCOUNT_KEY\",\n    \"0-0\": \"`Instances`\",\n    \"0-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"1-0\": \"`Class` - list\",\n    \"1-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"2-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"2-0\": \"`Class` - details\",\n    \"3-0\": \"`Class` - create\",\n    \"4-0\": \"`Class` - update\",\n    \"5-0\": \"`Class` - delete\",\n    \"5-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"4-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"3-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"6-0\": \"`Data Object`\",\n    \"6-2\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"7-0\": \"`Scripts`\",\n    \"7-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"8-0\": \"`Templates`\",\n    \"8-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"9-0\": \"`Data Endpoints` - list\",\n    \"9-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"10-0\": \"`Data Endpoints` - details\",\n    \"10-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"11-0\": \"`Data Endpoints` - other calls\",\n    \"11-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"12-0\": \"`Script Endpoints` - run public\",\n    \"12-1\": \"<div style=\\\"text-align: center\\\">ANYONE</div>\",\n    \"12-2\": \"<div style=\\\"text-align: center\\\">ANYONE</div>\",\n    \"12-3\": \"<div style=\\\"text-align: center\\\">ANYONE</div>\",\n    \"13-0\": \"`Script Endpoints` - other calls\",\n    \"13-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"14-0\": \"`Schedules`\",\n    \"14-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"15-0\": \"`Triggers`\",\n    \"15-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"16-0\": \"`Users` - list\",\n    \"16-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"17-0\": \"`Users` - details\",\n    \"17-2\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"18-0\": \"`Users` - add\",\n    \"18-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div><div style=\\\"color: black\\\">(With Allow user creation flag enabled)</div>\",\n    \"19-0\": \"`Users` - update\",\n    \"19-2\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"20-0\": \"`Users` - reset user key\",\n    \"20-2\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"21-0\": \"`Users` - delete\",\n    \"21-3\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"22-0\": \"`User` - log in\",\n    \"22-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"23-0\": \"`User` - social log in\",\n    \"23-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"24-0\": \"`User` - details\",\n    \"24-2\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"25-0\": \"`Push Notifications` (Apple & Android)\",\n    \"25-2\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"26-0\": \"`Channels` - listen to channel / room\",\n    \"26-1\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"27-0\": \"`Channels` - other calls\",\n    \"27-2\": \"<div style=\\\"color: green; text-align: center\\\">&#x2713;</div>\",\n    \"h-0\": \"Syncano call type\"\n  },\n  \"cols\": 4,\n  \"rows\": 28\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Summary\"\n}\n[/block]\nThat's all there is to know about permissions on Syncano Platform. To sum it up:\n- You can give to an `owner`, `group` or `other` categories, different sets of permissions, by assigning them adequate permission types.\n- An API Key with the `ignore_acl` flag set to `true` will ignore all the permissions.\n- Your users will be authenticating with API Key and User Key combinations. Some of the endpoints will be scoped to only view data for that particular user.\n\nSince you've learned how to set up permissions on Syncano, you might like to read about organizing users into [Groups](groups). If you already know how to do that, you may be interested in how [realtime communication](realtime-communication) works.","excerpt":"In this chapter you'll learn:\n- How to properly set up right Permissions for resources stored on Syncano \n- How to use the API and User Key combination","slug":"permissions","type":"basic","title":"Permissions"}

Permissions

In this chapter you'll learn: - How to properly set up right Permissions for resources stored on Syncano - How to use the API and User Key combination

Chapter sections: 1. [Overview](#overview) 2. [Permissions](#permissions) 3. [Permission Types](#permission-types) 4. [Using API Keys and User Keys](#using-api-keys-and-user-keys) 5. [Using API Key with allow_anonymous_read flag](#using-api-key-with-allow_anonymous_read-flag) 6. [Syncano authentication keys](#syncano-authentication-keys) 7. [Summary](#summary) [block:api-header] { "type": "basic", "title": "Overview" } [/block] The permissions system was designed so that you can have control over what your application users have access to on Syncano. If you create a file storage app, you'd probably want the users to see their own files and not files of other users. That's exactly what you can achieve by setting up proper permissions. [block:api-header] { "type": "basic", "title": "Permissions" } [/block] The permissions system on Syncano is inspired by [UNIX file system permissions](http://en.wikipedia.org/wiki/File_system_permissions). When you configure permissions, you configure them for one of three categories: * `owner` * `group` * `other` The owner is a category that relates only to Data Objects. When a Data Object is created we can set a User as its `owner`. Groups are groups of Users (you can read more about creating groups in [this chapter](groups)). Others will be Users that are not an `owner` and are not assigned to a `group` that is connected with a resource (Data Objects, Data Classes and Channels). While `owner` only applies to Data Objects, `groups` and `other` categories can also be set for Data Classes and Channels. The table below should clarify the concept a bit more: [block:parameters] { "data": { "0-0": "`owner`", "0-1": "`owner_permissions`", "1-0": "`group`", "1-1": "`group_permissions`", "2-0": "`other`", "2-1": "`other_permissions`", "0-2": "Data Objects", "1-2": "Data Objects, Data Classes, Channels", "2-2": "Data Objects, Data Classes, Channels", "h-0": "Category", "h-1": "Property", "h-2": "Applies to", "0-3": "The owner's permissions determine what actions the owner of the Data Object can perform on the resource.", "1-3": "The groups permissions determine what actions a user in the group can perform on a resource.", "2-3": "The permissions for others indicate what action all other users can perform on the resource.", "h-3": "Description" }, "cols": 4, "rows": 3 } [/block] [block:callout] { "type": "info", "body": "Since Account Keys (administrators) and API Keys with ignore_acl set to true can ignore permissions, `other` relates only to users (who will authenticate with API Key and User Key combination).", "title": "other" } [/block] [block:api-header] { "type": "basic", "title": "Permission Types" } [/block] Permission types define the level at which a user can interact with a resource. They are represented as values that you can set for `owner_permissions`, `group_permissions` and `other_permissions` properties. These values are a bit different for: - [Data Objects](#section-permission-types-for-data-objects-) - [Data Classes](#section-permission-types-for-classes-) - [Channels](#section-permission-types-for-channels-) ## Permission Types for Data Objects: [block:parameters] { "data": { "0-0": "`none`", "1-0": "`read`", "2-0": "`write`", "3-0": "`full`", "h-0": "Permission Type", "h-1": "Description", "1-1": "Grants the capability to read the Data Object.", "2-1": "Grants the capability to read and write the Data Object.", "3-1": "Grants read/write permissions plus the possibility of deleting the Data Object.", "0-1": "Default mode where users don't have access to the Data Object." }, "cols": 2, "rows": 4 } [/block] ### Examples If you never dealt with UNIX file system permissions, the concept might be a bit vague at first. We'll try to explain with a couple of examples. Let's consider 3 scenarios, when a User with an `id` = 123 will be able to read a Data Object with an `id`=1: 1. If a User is an `owner` and `owner_permissions` is `read` or higher (`write` or `full`), this is how the Data Object permission properties will look (non-permission properties removed for clarity): [block:code] { "codes": [ { "code": "{\n \"id\": 1, \n \"owner\": 123, \n \"owner_permissions\": \"read\", \n \"group\": null, \n \"group_permissions\": \"none\", \n \"other_permissions\": \"none\"\n}", "language": "json" } ] } [/block] 2. If the user belongs to a `group` associated with that Data Object and that Data Object has `group_permissions` = `read` or higher. If our user belonged to a Group with `id` 321, then this is how the Data Object permission settings could look like: [block:code] { "codes": [ { "code": "{\n \"id\": 1, \n \"owner\": null, \n \"owner_permissions\": \"none\", \n \"group\": 321, \n \"group_permissions\": \"read\", \n \"other_permissions\": \"none\"\n}", "language": "json" } ] } [/block] 3. Last check is `other_permissions`. Our user with an id = `123` is not an owner of the Data Object and doesn't belong to a group that is connected with this Data Object. Nevertheless the user can still read the Data Object because `other_permissions` are set to `read`: [block:code] { "codes": [ { "code": "{\n \"id\": 1, \n \"owner\": null, \n \"owner_permissions\": \"none\", \n \"group\": null, \n \"group_permissions\": \"none\", \n \"other_permissions\": \"read\"\n}", "language": "json" } ] } [/block] [block:callout] { "type": "warning", "body": "If a Data Object has `other_permissions` = `full`, it overrides all other permissions completely. So even if a user is not an `owner` and not in a `group` connected with the Data Object, the user will still have access to a Data Object where `other_permissions` = `full`. Same rule applies to Data Classes and Channels." } [/block] ### Creating a Data Object with an `owner_permissions` example [block:callout] { "type": "info", "body": "To see full guide on adding Data Objects, please see [this chapter](doc:data-objects) of Developer Manual." } [/block] It's worth noting that when a Data Object is created, its `owner_permissions` are `none` by default. What it means is that even if your user creates a Data Object, the user won't have access to it. [block:image] { "images": [ { "image": [ "https://files.readme.io/3aQEz5rQ4eTw8mHDi8Kc_Add_data_object_01.png", "Add_data_object_01.png", "1679", "872", "#264472", "" ] } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/8173iRWPSoCg5Zmi2zXw_Add_data_object_02.png", "Add_data_object_02.png", "1679", "873", "#849cb4", "" ] } ] } [/block] To make sure the user has access you should set the `owner_permissions` to `read` or higher during Data Object creation: [block:image] { "images": [ { "image": [ "https://files.readme.io/2xi5jtkQOyGBmswATBAX_Add_data_object_03.png", "Add_data_object_03.png", "1679", "872", "#6c84a4", "" ] } ] } [/block] Same rules apply when you create Data Objects in code: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: API_KEY\" \\\n-H \"X-USER-KEY: USER_KEY\" \\\n-H \"Content-type: application/json\" \\\n-d '{\"data\": \"I am sample data\",\"owner_permissions\":\"read\"}' \\\n\"https://api.syncano.io/v1.1/instances/<INSTANCE>/classes/<DATA_CLASS>/objects/\"", "language": "curl" }, { "code": "from syncano.models import User\nimport syncano\n\nsyncano.connect(api_key=\"API_KEY\") \n\ndata_object = Object.please.create(\n instane_name=\"INSTANCE_NAME\",\n \tclass_name=\"CLASS_NAME\",\n owner_permissions='read',\n)", "language": "python" }, { "code": "var Syncano = require('syncano'); //CommonJS\nvar instance = new Syncano({\n apiKey: API_KEY, \n instance: INSTANCE_NAME,\n userKey: USER_KEY\n});\n\nvar obj = {\"data\": \"I am sample data\",\"owner_permissions\":\"read\"};\n\ninstance.class('CLASS_NAME').dataobject(obj, callback());", "language": "javascript" }, { "code": "ExampleObject obj = new ExampleObject();\nobj.setOwnerPermissions(DataObjectPermissions.READ);\nobj.data = \"I am sample data\";\nResponse<ExampleObject> response = obj.save();", "language": "java", "name": "Android" }, { "code": "// Coming soon!", "language": "objectivec" }, { "code": "// Coming soon!", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "ExampleObject exampleObject = new ExampleObject();\nexampleObject.OwnerPermissions = DataObjectPermissions.READ;\nexampleObject.data = \"SOME_DATA\";\n\nsyncano.Please().Save(exampleObject, OnSuccess, OnFailure);", "language": "text", "name": "Unity" } ] } [/block] ## Permission Types for Data Classes: Permission types for Data Classes are different from the ones for Data Objects, because they not only consider access to a Data Class itself but also to the Data Objects that belong to that Data Class. So if you would like a user to have `read` access to a certain Data Object, you should not only grant that user access to that Data Object but also set its Data Class permissions to `read`. If you would like your users to be able to create Data Objects within a Data Class, the Data Class should have `create_objects` permission type set for those users (for a group users belongs to, or for `others` - which will affect every other user inside your Syncano Instance). [block:parameters] { "data": { "0-0": "`none`", "1-0": "`read`", "2-0": "`create_objects`", "h-0": "Permission Type", "h-1": "Description", "0-1": "Users don't have access to a Data Class and they won't be able to create Data Objects with this Data Class schema.", "1-1": "Means that users can get Data Class info + read Data Objects associated with that Data Class (provided that Data Objects permissions are set for read or higher for the specific user).", "2-1": "Default state. Users can read and create Data Objects within that Data Class." }, "cols": 2, "rows": 3 } [/block] [block:callout] { "type": "warning", "body": "When a Data Class is being created it's `group_permissions` and `other_permissions` will be `create_objects` by default. This way your application users will have an ability to create Data Objects in all of the Data Classes within an Instance. If you'd like to limit their access you can change the Data Class permissions to `read` or `none`." } [/block] ### Example We'll go through granting users permission to create Data Objects within a Data Class. We'll create a simple Data Class, with only one field ("title") that has `other_permissions` = `create_objects`. This way any user will be able to add and read Data Objects within this Data Class. [block:image] { "images": [ { "image": [ "https://files.readme.io/91bc042-add_class_permisions.png", "add_class_permisions.png", 1938, 1530, "#f7f7f7" ] } ] } [/block] [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"Content-type: application/json\" \\\n-H \"X-API-KEY: ACCOUNT_KEY\" \\\n-d '{\"name\": <data_class_name>,\n \"other_permissions\":\"create_objects\",\n \"schema\":[{\"type\":\"string\",\"name\":\"title\"}]}' \\\n\"https://api.syncano.io/v1.1/instances/<instance>/classes/\"", "language": "curl" }, { "code": "import python\nfrom syncano.models import Class\n\nsyncano.connect(api_key=\"API_KEY\")\n\nClass.please.create(\n instance_name=\"INSTANCE_NAME\",\n name=\"CLASS_NAME\",\n other_permissions=\"create_objects\",\n schema=[{'name':'title','type':'string'}]\n)", "language": "python" }, { "code": "var Syncano = require('syncano'); //CommonJS\nvar account = new Syncano({accountKey: ACCOUNT_KEY});\n\nvar options = {\n \"name\": CLASS_NAME,\n \"other_permissions\":\"create_objects\",\n \"schema\":[{\"type\":\"string\",\"name\":\"title\"}]\n};\n\naccount.instance('INSTANCE_NAME').class().add(options, callback());", "language": "javascript" }, { "code": "SyncanoClass syncanoClass = new SyncanoClass(ExampleObject.class);\nsyncanoClass.setOtherPermissions(SyncanoClassPermissions.CREATE_OBJECTS);\n\nResponse<SyncanoClass> response = syncano.createSyncanoClass(syncanoClass).send();", "language": "java", "name": "Android" }, { "code": "// Not supported in iOS Library - please use our Dashboard instead", "language": "objectivec" }, { "code": "// Not supported in iOS Library - please use our Dashboard instead", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" } ] } [/block] And that's it! Now any user can create and read objects in this data class. If you'd like to create more fine-grained permissions, you could create a group and add selected users to it. Next, when creating a Data Class, you'd set `group_permissions` to `create_objects` and pass a group id to the `group` parameter: [block:image] { "images": [ { "image": [ "https://files.readme.io/qvIeD7raRoCveb9q3L46_Add_class_04.png", "Add_class_04.png", "1678", "871", "#274470", "" ] } ] } [/block] [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"Content-type: application/json\" \\\n-H \"X-API-KEY: ACCOUNT_KEY\" \\\n-d '{\"name\": <data_class_name>,\n \"group_permissions\":\"create_objects\",\n \"group\": group_id,\n \"schema\":[{\"type\":\"string\",\"name\":\"title\"}]}' \\\n\"https://api.syncano.io/v1.1/instances/instance/classes/\"", "language": "curl" }, { "code": "import python\nfrom syncano.models.base import Class\n\nsyncano.connect(api_key=\"API_KEY\")\n\nClass.please.create(\n instance_name=\"INSTANCE_NAME\",\n name=\"CLASS_NAME\",\n group_permissions=\"create_objects\",\n group=1,\n schema=[{'name':'newer','type':'string'}]\n)", "language": "python" }, { "code": "var Syncano = require('syncano'); //CommonJS\nvar account = new Syncano({accountKey: ACCOUNT_KEY});\n\nvar options = {\n \"name\": CLASS_NAME,\n \"group_permissions\":\"create_objects\",\n \"group\": GROUP_ID,\n \"schema\":[{\"type\":\"string\",\"name\":\"title\"}]\n};\n\naccount.instance('INSTANCE_NAME').class().add(options, callback());", "language": "javascript" }, { "code": "SyncanoClass syncanoClass = new SyncanoClass(ExampleObject.class);\nsyncanoClass.setGroup(group.getId());\nsyncanoClass.setGroupPermissions(SyncanoClassPermissions.CREATE_OBJECTS);\n\nResponse<SyncanoClass> response = syncano.createSyncanoClass(syncanoClass).send();", "language": "java", "name": "Android" }, { "code": "// Not supported in iOS Library - please use our Dashboard instead", "language": "objectivec" }, { "code": "// Not supported in iOS Library - please use our Dashboard instead", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" } ] } [/block] ## Permission Types for Channels: [block:parameters] { "data": { "h-0": "Permission Type", "h-1": "Description", "0-0": "`none`", "1-0": "`subscribe`", "2-0": "`publish`", "0-1": "Default mode where users don't have access to channel notifications.", "1-1": "User can receive notifications from a channel.", "2-1": "User can publish data to a channel." }, "cols": 2, "rows": 3 } [/block] [block:callout] { "type": "info", "body": "Channels and their permissions are described in depth in the [Realtime Communication](realtime-communication) chapter of this manual." } [/block] [block:api-header] { "type": "basic", "title": "Using API Keys and User Keys" } [/block] Creating API Keys was described in our [Getting Started section](getting-started-with-syncano#getting-an-api-key) and you can read a bit more about User Keys in the [User management chapter](user-management#user-authentication). When it comes to permissions, it is important to know that there are two flags that can be set when creating an API Key: * `allow_user_create` - API Key with this flag set to `true` works on the instances/<instance>/users/ endpoint and enables user creation (you can read about adding new users [here](user-management#adding-a-user)). * `ignore_acl` - API Key with this flag set to `true` will ignore access control list. What this means is that it will ignore any permissions set for the resources in Syncano. * [`allow_anonymous_usage`](#using-api-key-with-allow_anonymous_read-flag) - When set to `true`, API Key with `allow_anonymous_read` will allow making GET requests to Data Classes and Data Objects based on appropriate permissions. [block:callout] { "type": "info", "title": "ignore_acl", "body": "For example a User that will use a combination of a User Key and an API Key with `ignore_acl` = true will be able to view all Data Objects in a Data Class where normally permissions would prohibit that user to have read access. The user could also create Data Objects in a Data Class where this Data Class doesn't have permission type `create_objects` etc. So, for instance, `ignore_acl` API Keys might be useful if you'd like to have Admin/Moderator Users. You should be careful though because such users would have large control within an instance along with the ability to create/delete Data Classes." } [/block] Depending on what you'd like to achieve in your app, you can either use an API Key or a combination of an API Key and a User Key. ## Using an API Key An API Key without `ignore_acl` or `create_user` flags has a rather limited access and mostly can only be used to read data from different endpoints. This is how specific API Key permissions per endpoint look like (endpoints that API Key doesn't have permission to view were omitted): [block:parameters] { "data": { "h-0": "Endpoint", "h-1": "Permission", "0-0": "/instances/", "1-0": "/api_keys/", "2-0": "/user/auth/", "3-0": "/users/", "4-0": "/groups/", "5-0": "/classes/", "6-0": "/classes/<class>/objects/", "7-0": "/channels/", "8-0": "/channels/<id>/publish/", "9-0": "/channels/<id>/history/", "9-1": "`read`", "8-1": "`write`", "7-1": "`read`", "6-1": "`create`", "5-1": "`read`", "4-1": "`read`", "3-1": "", "1-1": "`read`", "0-1": "`read`", "0-2": "Can view only the instance that the API Key belongs to.", "1-2": "Can view only own API Key (use account_key or the Syncano Dashboard to view full list of API Keys)", "3-2": "No read permission - not possible to list all the users. It's possible to add new users when API Key has `allow_user_create` = true.", "5-2": "Can view data classes when data class permission types are set to `read` or `create_objects`.", "6-2": "- Can create new objects inside a data class when the data class has `create_objects` permission set. \n- Can read/write/update/delete objects depending on specific Data Object owner/group/other permissions + also requires data class permission types to be `read` or `create_objects`.", "7-2": "Can view channels if channel permission types are set to `subscribe` or `publish`.", "8-2": "Can `write` to a channel if channel permission types are set to `publish`.", "9-2": "Can `read` a channel if channel permissions are `subscribe` or `publish`.", "h-2": "Description", "2-2": "Endpoint where user can POST their user credentials (log in using username and password) and get User Key in response.", "4-2": "Can view groups." }, "cols": 3, "rows": 10 } [/block] ## Using an API Key + User Key In most of the cases your users should be connecting to your app with a combination of User Key and API Key. If that's the case, then some endpoints will behave differently and will be showing data that is scoped for the current user. You'll find a list of these endpoints below: [block:parameters] { "data": { "0-0": "/user/", "0-1": "`write`", "0-2": "Endpoint available only with API Key + User Key (Account Key + User Key won't work here!). A User can view only their account details and change their username and/or password.", "1-0": "/users/", "1-2": "A User can view only their account details on the list.", "1-1": "`write`", "3-0": "/users/<id>/groups/", "3-1": "`read`", "3-2": "A User can see only these Groups that he is a part of.", "4-1": "`read`", "4-0": "/groups/<id>/users/", "4-2": "A User can only see themself being a part of a Group.", "h-0": "Endpoint", "h-1": "Permission", "h-2": "Description", "2-0": "/users/<user_id>/", "2-1": "`write`", "2-2": "A User can view their account details and change their username and/or password." }, "cols": 3, "rows": 5 } [/block] [block:callout] { "type": "info", "body": "The Rest of the endpoints will behave in the same manner as if accessed only with an API Key." } [/block] [block:api-header] { "type": "basic", "title": "Using API Key with allow_anonymous_read flag" } [/block] When set to `true`, API Key with allow_anonymous_read will allow making GET requests to Data Classes and Data Objects *provided that*: - Data Objects have `other_permissions` set to `read`, `write` or `full` - Data Classes have `other_permissions` set to `read` or `create_objects` [block:callout] { "type": "info", "body": "Please refer to the permissions section [above](#permissions) if you want to learn how to add permissions to Data Classes and Data Objects." } [/block] What is important here is that this key will have *read* access to all the resources with appropriate permissions without the necessity to pass a User API Key along with it. It might come handy in cases where you'd like some of your apps resources to be accessible without the need for user authentication. ### Adding an API Key with allow_anonymous_read flag This is how you can create allow_anonymous_read API Key: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: ACCOUNT_KEY\" \\\n-H \"Content-type: application/json\" \\\n-d '{\"allow_anonymous_read\": true}' \\\n\"https://api.syncano.io/v1.1/instances/INSTANCE/api_keys/\"", "language": "curl" }, { "code": "import syncano\nfrom syncano.models import ApiKey\n\nsyncano.connect(api_key='API_KEY')\n\napi_key = ApiKey.please.create(allow_anonymous_read=True)\n", "language": "python" }, { "code": "// Coming soon!", "language": "javascript" }, { "code": "// Not supported", "language": "java", "name": "Android" }, { "code": "// Coming soon!", "language": "objectivec" }, { "code": "// Coming soon!", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "// NOT AVAILABLE", "language": "csharp", "name": "Unity" } ] } [/block] Response (some properties omitted for clarity): [block:code] { "codes": [ { "code": "{\n \"allow_anonymous_read\": true,\n \"allow_user_create\": false,\n \"api_key\": \"cc308b5a686e1ad3e7290717e2b36e11193184d5\",\n \"id\": 2581,\n \"ignore_acl\": false\n}", "language": "curl" }, { "code": "# RAW RESPONSE\n{\n 'description': u'', \n 'links': <syncano.models.fields.LinksWrapper object at 0x7f04094e55d0>, \n 'allow_anonymous_read': True, \n 'allow_user_create': False, \n 'instance_name': 'INSTANCE_NAME', \n 'api_key': 'API_KEY', \n 'id': ID, \n 'ignore_acl': False\n}\n\n# CODE:\nprint(api_key.allow_anonymous_read)\n>> True", "language": "python" }, { "code": "// Coming soon!", "language": "javascript" }, { "code": "// Coming soon!", "language": "objectivec" }, { "code": "// Coming soon!", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" } ] } [/block] [block:api-header] { "type": "basic", "title": "Syncano authentication Keys" } [/block] The following table shows some of the more commonly used API Endpoints and the specific authentication keys that have the proper permissions to make these calls: [block:parameters] { "data": { "h-1": "API_KEY", "h-2": "API_KEY & USER_KEY", "h-3": "ACCOUNT_KEY", "0-0": "`Instances`", "0-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "1-0": "`Class` - list", "1-1": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "2-1": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "2-0": "`Class` - details", "3-0": "`Class` - create", "4-0": "`Class` - update", "5-0": "`Class` - delete", "5-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "4-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "3-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "6-0": "`Data Object`", "6-2": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "7-0": "`Scripts`", "7-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "8-0": "`Templates`", "8-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "9-0": "`Data Endpoints` - list", "9-1": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "10-0": "`Data Endpoints` - details", "10-1": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "11-0": "`Data Endpoints` - other calls", "11-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "12-0": "`Script Endpoints` - run public", "12-1": "<div style=\"text-align: center\">ANYONE</div>", "12-2": "<div style=\"text-align: center\">ANYONE</div>", "12-3": "<div style=\"text-align: center\">ANYONE</div>", "13-0": "`Script Endpoints` - other calls", "13-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "14-0": "`Schedules`", "14-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "15-0": "`Triggers`", "15-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "16-0": "`Users` - list", "16-1": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "17-0": "`Users` - details", "17-2": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "18-0": "`Users` - add", "18-1": "<div style=\"color: green; text-align: center\">&#x2713;</div><div style=\"color: black\">(With Allow user creation flag enabled)</div>", "19-0": "`Users` - update", "19-2": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "20-0": "`Users` - reset user key", "20-2": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "21-0": "`Users` - delete", "21-3": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "22-0": "`User` - log in", "22-1": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "23-0": "`User` - social log in", "23-1": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "24-0": "`User` - details", "24-2": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "25-0": "`Push Notifications` (Apple & Android)", "25-2": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "26-0": "`Channels` - listen to channel / room", "26-1": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "27-0": "`Channels` - other calls", "27-2": "<div style=\"color: green; text-align: center\">&#x2713;</div>", "h-0": "Syncano call type" }, "cols": 4, "rows": 28 } [/block] [block:api-header] { "type": "basic", "title": "Summary" } [/block] That's all there is to know about permissions on Syncano Platform. To sum it up: - You can give to an `owner`, `group` or `other` categories, different sets of permissions, by assigning them adequate permission types. - An API Key with the `ignore_acl` flag set to `true` will ignore all the permissions. - Your users will be authenticating with API Key and User Key combinations. Some of the endpoints will be scoped to only view data for that particular user. Since you've learned how to set up permissions on Syncano, you might like to read about organizing users into [Groups](groups). If you already know how to do that, you may be interested in how [realtime communication](realtime-communication) works.