{"__v":33,"_id":"56a0bda13697d80d002ac60b","category":{"__v":3,"_id":"56a0bd9f3697d80d002ac5e9","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"],"project":"54774d9af3736008009e9e0e","version":"56a0bd9e3697d80d002ac5e7","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-02-05T14:34:09.364Z","from_sync":false,"order":17,"slug":"developer-manual","title":"Advanced Topics"},"parentDoc":null,"project":"54774d9af3736008009e9e0e","user":"54774c47f3736008009e9e0c","version":{"__v":20,"_id":"56a0bd9e3697d80d002ac5e7","project":"54774d9af3736008009e9e0e","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"},"updates":["558bed7e5006113900593c8a","576807c100ca540e00cf28b8"],"next":{"pages":[],"description":""},"createdAt":"2015-05-13T11:26:02.378Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":4,"body":"1. [Creating an API Key with user creation permissions](#creating-an-api-key-with-user-creation-permissions)\n2. [Adding a User](#adding-a-user)\n3. [User Profiles](#user-profiles)\n4. [Updating user profiles](#updating-user-profiles)\n5. [Resetting a User Key](#resetting-a-user-key) \n6. [User authentication](#user-authentication)\n7. [Social Login](#social-login)\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Creating an API Key with user creation permissions\"\n}\n[/block]\nTo be able to register Users you'll have to create an API Key that has `allow_user_create` flag set to `true` (It is possible to create new Users with the Account Key but it's not the recommended solution). \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/6ckpRxxVSlqs9LPlZA4g_Add_API_Key_01.png\",\n        \"Add_API_Key_01.png\",\n        \"1277\",\n        \"665\",\n        \"#27446f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/s6tbgYiBSFWDvMN9jo0c_Add_API_Key_02.png\",\n        \"Add_API_Key_02.png\",\n        \"1679\",\n        \"872\",\n        \"#849cb4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nBefore confirming, in **step 5.**, please change the switch state in `User registration?` line - this way this API Key will be able to add new users to your Syncano Instance.\n\nThis is an example of such API Key creation call:\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_user_create\\\":true}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/instance/api_keys/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"from syncano.models import ApiKey\\nimport syncano\\n\\nsyncano.connect(api_key=\\\"API_KEY\\\")\\n\\nnew_key = ApiKey.please.create(\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    allow_user_create=True\\n)\\n\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");  // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar ApiKey = connection.ApiKey;\\n\\nvar options = {\\n  allow_user_create: true, \\n  instanceName: \\\"INSTANCE_NAME\\\"\\n};\\n\\nApiKey.please().create(options).then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"// Not supported in Android Library - please use Dashboard instead.\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"// Not supported in iOS Library - please use Dashboard instead.\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// Not supported in iOS Library - please use Dashboard instead.\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"// Not supported in Unity Library - please use Dashboard instead.\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\n\nExample response:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"id\\\": 819, \\n    \\\"description\\\": \\\"\\\", \\n    \\\"api_key\\\": \\\"78997d74c0f71141e489a3284fb4f2e464abdc19\\\", \\n    \\\"ignore_acl\\\": false, \\n    \\\"allow_user_create\\\": true, \\n    \\\"created_at\\\": \\\"2015-04-21T14:19:41.309520Z\\\", \\n    \\\"links\\\": {\\n        \\\"self\\\": \\\"/v1.1/instances/<instance>/api_keys/819/\\\", \\n        \\\"reset_key\\\": \\\"/v1.1/instances/<instance>/api_keys/819/reset_key/\\\"\\n    }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nNow we can utilize this API Key in the `User add` API call:\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Adding a User\"\n}\n[/block]\nOnce we create the API Key with `allow_user_create` flag set to true (mentioned in a previous [section](#creating-an-api-key-with-user-creation-permissions)) adding new users is pretty straightforward. \n\nGo to `Users & Groups` tab in the Dashboard's Navigation Bar.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/HGf24vCwSZe83baXV9Rb_Add_user_01.png\",\n        \"Add_user_01.png\",\n        \"1679\",\n        \"736\",\n        \"#254472\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nWhen you click `Create a User` button, you will see a pop-up. Type there new user `username` and `password` and press `Confirm` to save.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/tVUevONOSmGUXOYlnPqV_Add_user_02.png\",\n        \"Add_user_02.png\",\n        \"1679\",\n        \"773\",\n        \"#254474\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nFor adding new user in code, please see the example below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: API_KEY_WITH_ALLOW_USER_CREATE_FLAG\\\" \\\\\\n-H \\\"Content-type: application/json\\\" \\\\\\n-d '{\\\"username\\\":\\\"Gordon Freeman\\\",\\\"password\\\":\\\"Black Mesa\\\"}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/users/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"from syncano.models import User\\nimport syncano\\n\\nsyncano.connect(api_key=\\\"API_KEY_WITH_ALLOW_USER_CREATE_FLAG\\\") \\n# You can use an account key as well\\n\\nGordon = User.please.create(\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    username=\\\"Gordon Freeman\\\",\\n    password=\\\"Black Mesa\\\"\\n)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");\\nvar connection = Syncano({apiKey: API_KEY_WITH_ALLOW_USER_CREATE_FLAG});\\nvar User = connection.User;\\n\\nvar options = {\\n  username: USERNAME, \\n  password: PASSWORD,\\n  instanceName: INSTANCE_NAME\\n};\\n\\nUser.please().create(options).then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"User newUser = new User(userName, password);\\nResponse<User> response = newUser.register();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"[Syncano sharedInstanceWithApiKey::::at:::\\\"API_KEY\\\" instanceName:@\\\"instance_name\\\"];\\n[SCUser registerWithUsername:username password:password completion:^(NSError *error) {\\n      //handle user registration\\n}];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Syncano.sharedInstanceWithApiKey(\\\"API_KEY\\\", instanceName: \\\"instance_name\\\")\\nSCUser.registerWithUsername(username, password: password) { error in\\n  //handle error\\n}\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"User<Profile> user =  new User<Profile>(\\\"username\\\", \\\"password\\\");\\nuser.Register(UserCreateCallback);\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\nExample response:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"id\\\": 66, \\n    \\\"username\\\": \\\"Gordon Freeman\\\", \\n    \\\"user_key\\\": \\\"33b966b883351528e4ee3206cd84bd42fcf2d4a4\\\", \\n    \\\"profile\\\": {\\n        \\\"id\\\": 1198, \\n        \\\"created_at\\\": \\\"2015-03-25T14:01:31.962783Z\\\", \\n        \\\"updated_at\\\": \\\"2015-03-25T14:01:31.962810Z\\\", \\n        \\\"revision\\\": 1, \\n        \\\"owner\\\": 66, \\n        \\\"owner_permissions\\\": \\\"full\\\", \\n        \\\"group\\\": null, \\n        \\\"group_permissions\\\": \\\"none\\\", \\n        \\\"other_permissions\\\": \\\"none\\\", \\n        \\\"channel\\\": null, \\n        \\\"channel_room\\\": null, \\n        \\\"links\\\": {\\n            \\\"owner\\\": \\\"/v1.1/instances/<instance>/users/66/\\\", \\n            \\\"self\\\": \\\"/v1.1/instances/<instance>/classes/user_profile/objects/1198/\\\"\\n        }\\n    }, \\n    \\\"links\\\": {\\n        \\\"self\\\": \\\"/v1.1/instances/<instance>/users/66/\\\", \\n        \\\"reset-key\\\": \\\"/v1.1/instances/<instance>/users/66/reset_key/\\\", \\n        \\\"groups\\\": \\\"/v1.1/instances/<instance>/users/66/groups/\\\"\\n    }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nWhoa! Quite a lot of info in this User object! Let's break it down, so that it's a bit easier to digest. If we omit the `profile` property(we'll get back to it in a moment), this is how User object looks like:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"id\\\": 66, \\n    \\\"username\\\": \\\"Gordon Freeman\\\", \\n    \\\"user_key\\\": \\\"33b966b883351528e4ee3206cd84bd42fcf2d4a4\\\", \\n    \\\"profile\\\": {...}, \\n    \\\"links\\\": {...}\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nOk, so this is a bit simpler. What we've got here is:\n[block:parameters]\n{\n  \"data\": {\n    \"0-0\": \"id\",\n    \"h-0\": \"Property\",\n    \"h-1\": \"Description\",\n    \"0-1\": \"User id\",\n    \"1-0\": \"username\",\n    \"1-1\": \"Name of the user that was provided during registration\",\n    \"2-0\": \"user_key\",\n    \"2-1\": \"User authentication key. Should be used when making calls to the `/user` endpoint\",\n    \"3-0\": \"profile\",\n    \"3-1\": \"User profile object\",\n    \"4-0\": \"links\",\n    \"4-1\": \"HATEOAS links to connected resources\"\n  },\n  \"cols\": 2,\n  \"rows\": 5\n}\n[/block]\nAt this point you might probably ask \"Ok, wait a sec! What exactly is this `profile` thing?\". We'll explain it in the next section which is called (you'll never guess)...\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"User Profiles\"\n}\n[/block]\nAs you may have noticed when browsing through the API or Admin GUI, there's an extra default Data Class sitting in each Instance that you create. This Data Class, called \"user_profile\", stores Data Objects, which are the profiles of your Users. So, whenever a new User is added, a special \"profile\" Data Object is being created. The user_profile Data Class and its Data Objects profiles are protected, which means that no one can delete the user_profile Data Class, create new user profiles manually, delete profiles, or change ownership of the profile (user is always their profile owner).\n\n### Why should I care?\n\nExcellent question! Since user profiles are just Data Objects stored in a Data Class, you can simply change this Data Class Schema to add custom fields.\n\n### Example\n\nLet's say you'd like your users to have the ability to add profile pictures. What we'll do, is change the 'user_profile' Data Class to have an 'avatar' field.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"If you'd like a reminder of what Data Class or Data Class Schema is, please see [this chapter](http://docs.syncano.io/docs/classes-overview).\"\n}\n[/block]\n1. Go to Data Classes Tab in the [Dashboard](https://dashboard.syncano.io). As you see, `user_profile` data class is already there, no need to create it. To edit this data class, click on dropdown icon.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/O2pIv4ctSCyk17goajbS_Edit_user_profile_01.png\",\n        \"Edit_user_profile_01.png\",\n        \"1679\",\n        \"767\",\n        \"#264471\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nChoose `Edit a Data Class` option from the dropdown.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/8G01qSnQGWMP23XXgKCj_Edit_user_profile_02.png\",\n        \"Edit_user_profile_02.png\",\n        \"1679\",\n        \"770\",\n        \"#254473\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nEnter new field name and type (in our example it would be `avatar` field of type `file`) and click `ADD` next to it. Press `Update` to save changes.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/44d3eb7-update_class.png\",\n        \"update_class.png\",\n        1924,\n        1532,\n        \"#f8f8f2\"\n      ]\n    }\n  ]\n}\n[/block]\nYou can make same kind of changes to `user_profile` data class, using our API:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X PATCH \\\\\\n-H \\\"X-API-KEY: ACCOUNT_KEY\\\" \\\\\\n-d schema='[{\\\"name\\\":\\\"avatar\\\",\\\"type\\\":\\\"file\\\"}]' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/user_profile/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import syncano \\n\\nconnection = syncano.connect('ACCOUNT_KEY')\\n\\nClass = connection.Class\\n\\nuser_profile_class = Class.please.get(\\n    instance_name='instance_name',\\n    name='user_profile'\\n)\\n\\nuser_profile_class.schema.add({\\\"name\\\": \\\"avatar\\\", \\\"type\\\": \\\"file\\\"})\\nuser_profile_class.save()\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");  // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar Class = connection.Class;\\n\\nvar query = {\\n\\tinstanceName: \\\"INSTANCE_NAME\\\",\\n  className: \\\"user_profile\\\"\\n};\\n\\nvar update = {\\n\\tschema : [{\\\"name\\\":\\\"avatar\\\",\\\"type\\\":\\\"file\\\"}]\\n};\\n\\nClass.please().update(query, update).then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"// MyUserProfile should extend Profile class\\nResponse<SyncanoClass> response = syncano.updateSyncanoClass(MyUserProfile.class).send();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"// You cannot change class schema from iOS, but it's really easy to do using our Dashboard!\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// You cannot change class schema from iOS, but it's really easy to do using our Dashboard!\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    }\n  ]\n}\n[/block]\nNow a user has an extra `avatar` field in their user profile, which the user can update with an avatar picture:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X PATCH \\\\\\n-H \\\"X-API-KEY: API_KEY\\\" \\\\\\n-H \\\"X-USER-KEY: USER_KEY\\n-H \\\"Content-type:multipart/form-data\\\" \\\\\\n-F name=\\\"avatar\\\" \\\\\\n-F filename=@user_avatar_file \\\\\\n-k \\\"https://api.syncano.io/v1.1/instances/instance/classes/user_profile/objects/4328/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import syncano\\nfrom syncano.models import Object\\n\\nconnection = syncano.connect(api_key='API_KEY')\\n\\nimage_path = \\\"/sample_path/user_avatar.jpg\\\"\\navatar= open(image_path, \\\"r\\\")\\n\\nObject.please.update(\\n  \\tid=ID\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    class_name=\\\"CLASS_NAME\\\",\\n    avatar=avatar\\n)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var fs = require(\\\"fs\\\");\\nvar Syncano = require(\\\"syncano\\\");  // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar DataObject = connection.DataObject;\\n\\nvar object = {\\n  id: ID\\n  avatar: Syncano.file(fs.readFileSync('/sample_path/user_avatar.jpg')),\\n  instanceName: \\\"INSTANCE_NAME\\\",\\n  className: \\\"CLASS_NAME\\\"\\n};\\n\\nDataObject.please().update(object).then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"MyUserProfile profile = user.getProfile();\\nprofile.avatar = new SyncanoFile(new File(getAssetsDir(), \\\"blue.png\\\"));\\nResponse<MyUserProfile> responseAvatar = profile.save();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"@interface MyUserProfile : SCUserProfile\\n@property (nonatomic, strong) SCFile *avatar;\\n@end\\n\\n@interface MyUser : SCUser\\n@property (nonatomic,retain) MyUserProfile *profile;\\n@end\\n\\n@implementation MyUserProfile\\n@end\\n  \\n@implementation MyUser\\n@dynamic profile;\\n@end\\n  \\n[Syncano sharedInstanceWithApiKey:@\\\"API_KEY\\\" instanceName:@\\\"instance_name\\\"];\\n//call this once, before you interact with Syncano in any way\\n[MyUser registerClassWithProfileClass:[MyUserProfile class]];\\n//now it's safe to use custom profiles\\nMyUser *currentUser = [MyUser currentUser];\\nMyUserProfile *profile = currentUser.profile;\\nprofile.avatar = [SCFile fileWithaData:UIImageJPEGRepresentation([UIImage imageNamed:@\\\"imageName\\\"], 0.7)];\\n[profile saveWithCompletionBlock:^(NSError *error) {\\n  //handle error\\n}];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"class MyUserProfile : SCUserProfile {\\n    var avatar : SCFile? = nil;\\n}\\n\\nclass MyUser : SCUser {\\n    var myProfile : MyUserProfile? {\\n        get {\\n            return profile as? MyUserProfile\\n        }\\n        set {\\n            profile = newValue\\n        }\\n    }\\n}\\n\\nSyncano.sharedInstanceWithApiKey(\\\"API_KEY\\\", instanceName: \\\"instance_name\\\")\\n//call this once, before you interact with Syncano in any way\\nMyUser.registerClassWithProfileClass(MyUserProfile.self)\\n//now it's safe to use custom profiles\\nlet currentUser = MyUser.currentUser()\\nlet profile = currentUser.myProfile\\nprofile?.avatar = SCFile(withaData: UIImageJPEGRepresentation(UIImage(named: \\\"imageName\\\")!, 0.7))\\nprofile?.saveWithCompletionBlock() { error in\\n  //handle error\\n}\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"User<TestProfile> user =  new User<TestProfile>(\\\"username\\\", \\\"password\\\");\\n\\nyield return user.Login(UserCallbackSuccess, UserCallbackFail); //Wait until we successfully login.\\n\\nSyncanoFile avatar = new SyncanoFile(AvatarImage.sprite.texture.EncodeToPNG());\\n\\nuser.Profile = new TestProfile(avatar);\\nuser.UpdateCustomUser(UserCallbackSuccess, UserCallbackFail);\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\nAnd voila! The User profile just got a new shiny avatar image:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"id\\\": 4328, \\n    \\\"created_at\\\": \\\"2015-04-21T11:31:54.249412Z\\\", \\n    \\\"updated_at\\\": \\\"2015-04-23T14:11:26.603282Z\\\", \\n    \\\"revision\\\": 7, \\n    \\\"owner\\\": 1429, \\n    \\\"owner_permissions\\\": \\\"none\\\", \\n    \\\"group\\\": null, \\n    \\\"group_permissions\\\": \\\"none\\\", \\n    \\\"other_permissions\\\": \\\"none\\\", \\n    \\\"channel\\\": null, \\n    \\\"channel_room\\\": null, \\n    \\\"avatar\\\": {\\n        \\\"type\\\": \\\"file\\\", \\n        \\\"value\\\": \\\"https://api.syncano.io.s3.amazonaws.com/1/5/7aecf4b79f8f033caf9cc2619ee4d14e6bda8832.jpg\\\"\\n    }, \\n    \\\"links\\\": {...}\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"User authentication\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"To authenticate a user, you'll need to make a call to the `/user/` endpoint. This endpoint is unique in terms of authentication because to get or update the user details you will need to use a combination of an api_key and user_key.\\n\\naccount_key will not work in this endpoint!\",\n  \"title\": \"Important!\"\n}\n[/block]\nUser authentication is used when we want our users to be able to login to our application. For a successful User auth call we need user credentials (login and password) and an API Key. Here is an example of such call:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: API_KEY\\\" \\\\\\n-H \\\"Content-type: application/json\\\" \\\\\\n-d '{\\\"username\\\":\\\"Gordon Freeman\\\",\\\"password\\\":\\\"Black mesa\\\"}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/user/auth/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import syncano\\n\\nsyncano.connect(\\n    api_key=\\\"API_KEY\\\",\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    username=\\\"Gordon Freeman\\\",\\n    password=\\\"Black Mesa\\\"\\n)\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");\\nvar connection = Syncano({apiKey: \\\"API_KEY\\\"});\\nvar User = connection.User;\\n\\nvar query = {instanceName: \\\"INSTANCE_NAME\\\"};\\nvar credentials = {username: \\\"EMAIL\\\", password: \\\"PASSWORD\\\"};\\n\\nUser.please().login(query, credentials).then(function(res) {\\n  // userKey will be saved in a connection object and can be used\\n  // in further calls\\n  console.log(connection.userKey);\\n});\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"User plainUser = new User(userName, password);\\n\\nResponse<User> response = plainUser.on(userSyncano).login();\\n// All next requests will be used using apiKey and userKey.\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"[Syncano sharedInstanceWithApiKey:@\\\"API_KEY\\\" instanceName:@\\\"instance_name\\\"];\\n[SCUser loginWithUsername:username password:password completion:^(NSError *error) {\\n  //handle error\\n}];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Syncano.sharedInstanceWithApiKey(\\\"API_KEY\\\", instanceName: \\\"instance_name\\\")\\nSCUser.loginWithUsername(\\\"username\\\", password: \\\"password\\\") { error in\\n  //handle error\\n}\",\n      \"language\": \"javascript\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"User<Profile> user =  new User<Profile>(\\\"username\\\", \\\"password\\\");\\nuser.Login(UserCreateCallbackSuccess, UserCreateCallbackFail);\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\nUser login call returns `user_key` in the response:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"id\\\": 66, \\n    \\\"username\\\": \\\"Gordon Freeman\\\", \\n    \\\"user_key\\\": \\\"33b966b883351528e4ee3206cd84bd42fcf2d4a4\\\", \\n    \\\"profile\\\": {...}, \\n    \\\"links\\\": {...}\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"success\",\n  \"body\": \"`user_key` should be used along with `api_key` in all subsequent calls on the client side. So i.e. a call where a user is creating a Data Object would look like this:\"\n}\n[/block]\n\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 '{\\\"name\\\": \\\"I am an object name\\\"}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/instance_name/classes/class/objects/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"from syncano.models import Object\\nimport syncano\\n\\nsyncano.connect(\\n    api_key=\\\"API_KEY\\\",\\n    user_key=\\\"USER_KEY\\\",\\n    instance_name=\\\"INSTANCE_NAME\\\"\\n)\\n\\nObject.please.create(\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    class_name=\\\"CLASS_NAME\\\",\\n    name=\\\"I am a data object\\\"\\n)\\n\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");\\nvar connection = Syncano({apiKey: \\\"API_KEY\\\", userKey: \\\"USER_KEY\\\"});\\nvar DataObject = connection.DataObject;\\n\\nvar object = {\\n  instanceName: \\\"INSTANCE_NAME\\\", \\n  className: \\\"CLASS_NAME\\\",\\n\\tname: \\\"I am an object name\\\"\\n};\\n\\nDataObject.please().create(object).then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"syncano.setUserKey(userKey);\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"// In iOS you don't need to extract User Key manually - after logging in it will be used automatically\\n\\n[Syncano sharedInstanceWithApiKey:@\\\"API_KEY\\\" instanceName:@\\\"instance_name\\\"];\\n[SCUser loginWithUsername:username password:password completion:^(NSError *error) {\\n  Book *book = [Book new];\\n  book.title = @\\\"The Last Wish\\\";\\n  //this call will be made with User Key\\n  [book saveWithCompletionBlock:^(NSError *error) {\\n  }];\\n}];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// In iOS you don't need to extract User Key manually - after logging in it will be used automatically\\n\\nSyncano.sharedInstanceWithApiKey(\\\"API_KEY\\\", instanceName: \\\"instance_name\\\")\\nSCUser.loginWithUsername(\\\"username\\\", password: \\\"password\\\") { error in\\n  //handle error\\n  let book = Book()\\n  book.title = \\\"The Last Wish\\\"\\n  //this call will be made with User Key\\n  book.saveWithCompletionBlock { error in\\n  }\\n}\",\n      \"language\": \"javascript\",\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]\nThe `user_key` can be used for a prolonged period of time, because it expires only in the event of user changing his password. This way it is possible to store it within your application without the need to store the user’s password itself.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Updating user profiles\"\n}\n[/block]\nThere are three ways to update user profiles. You can do this manually by Syncano Dashboard and by endpoints. \n\n##Updating by user end-point\nFor updating specified user profile you need to use your API Key and User Key. You can see the example below:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X PATCH \\\\\\n-H \\\"X-API-KEY: <API_KEY>\\\" \\\\\\n-H \\\"X-USER-KEY: <USER_KEY>\\\" \\\\\\n-H \\\"Content-Type: application/json\\\" \\\\\\n-d '{\\\"username\\\":\\\"<new_username>\\\",\\n\\t   \\\"password\\\":\\\"<new_password>\\\"}' \\\\\\n\\\"https://api.syncano.io/v1/instances/<instance_name>/user/\\\" \",\n      \"language\": \"curl\",\n      \"name\": \"cURL\"\n    },\n    {\n      \"code\": \"var Syncano = require('syncano'); //CommonJS\\nvar instance = Syncano({instance: 'INSTANCE_NAME', apiKey: 'API_KEY', userKey: 'USER_KEY'});\\n\\nvar user = {\\n  \\\"username\\\":\\\"<new_username>\\\", \\n  \\\"password\\\":\\\"<new_password>\\\"\\n};\\n\\ninstance.user().update(user, callback());\",\n      \"language\": \"javascript\",\n      \"name\": \"JavaScript\"\n    }\n  ]\n}\n[/block]\nYou don't need to update all user parameters. You can update only one of them.  \n\nExample response: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"username\\\": \\\"sample_username\\\",\\n    \\\"profile\\\": {\\n        \\\"channel_room\\\": null,\\n        \\\"group\\\": null,\\n        \\\"links\\\": {\\n            \\\"owner\\\": \\\"/v1/instances/rivia/users/1/\\\",\\n            \\\"self\\\": \\\"/v1/instances/rivia/classes/user_profile/objects/1/\\\"\\n        },\\n        \\\"group_permissions\\\": \\\"none\\\",\\n        \\\"created_at\\\": \\\"2016-06-20T08:43:27.204105Z\\\",\\n        \\\"owner_permissions\\\": \\\"full\\\",\\n        \\\"updated_at\\\": \\\"2016-06-20T08:43:27.204122Z\\\",\\n        \\\"other_permissions\\\": \\\"none\\\",\\n        \\\"owner\\\": 1,\\n        \\\"age\\\": null,\\n        \\\"nickname\\\": null,\\n        \\\"id\\\": 1,\\n        \\\"channel\\\": null,\\n        \\\"revision\\\": 1\\n    },\\n    \\\"links\\\": {\\n        \\\"profile\\\": \\\"/v1/instances/rivia/classes/user_profile/objects/1/\\\",\\n        \\\"self\\\": \\\"/v1/instances/rivia/users/1/\\\",\\n        \\\"groups\\\": \\\"/v1/instances/rivia/users/1/groups/\\\",\\n        \\\"reset-key\\\": \\\"/v1/instances/rivia/users/1/reset_key/\\\"\\n    },\\n    \\\"user_key\\\": \\\"15e5b35e1cd8s8abf806f3e925951f2612bf0d20\\\",\\n    \\\"groups\\\": [\\n        {\\n            \\\"description\\\": \\\"\\\",\\n            \\\"id\\\": 1,\\n            \\\"links\\\": {\\n                \\\"self\\\": \\\"/v1/instances/rivia/groups/1/\\\",\\n                \\\"users\\\": \\\"/v1/instances/rivia/groups/1/users/\\\"\\n            },\\n            \\\"label\\\": \\\"main_group\\\"\\n        }\\n    ],\\n    \\\"id\\\": 1\\n}\",\n      \"language\": \"json\",\n      \"name\": null\n    }\n  ]\n}\n[/block]\n##Updating by users end-point\nSecond way to update user profile is to use `users end-point` as the sample below. In this case you need only API Key and user id.\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X PATCH \\\\\\n-H \\\"X-API-KEY: <API_KEY>\\\" \\\\\\n-H \\\"Content-Type: application/json\\\" \\\\\\n-d '{\\\"username\\\":\\\"<new_username>\\\",\\n     \\\"password\\\":\\\"<new_password>\\\"}' \\\\\\n\\\"https://api.syncano.io/v1/instances/<instance_name>/users/<user_id>/\\\"\",\n      \"language\": \"curl\",\n      \"name\": \"cURL\"\n    },\n    {\n      \"code\": \"from syncano.models import User\\nimport syncano\\n\\nsyncano.connect(api_key=\\\"API_KEY\\\")\\n\\nUser.please.update(instance_name=\\\"INSTANCE_NAME\\\",\\n                   ID=USER_ID,\\n                   username=\\\"NEW_USERNAME\\\",\\n                   password=\\\"NEW_PASSWORD\\\")\",\n      \"language\": \"python\",\n      \"name\": \"Python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar User = connection.User;\\n\\nvar query = {instanceName: INSTANCE_NAME, id: USER_ID};\\nvar update = {username: USERNAME, password: PASSWORD};\\n\\nUser.please().update(query, update).then(callback);\",\n      \"language\": \"javascript\",\n      \"name\": \"JavaScript\"\n    }\n  ]\n}\n[/block]\nExample response:\n\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"username\\\": \\\"another_username\\\",\\n    \\\"profile\\\": {\\n        \\\"channel_room\\\": null,\\n        \\\"group\\\": null,\\n        \\\"links\\\": {\\n            \\\"owner\\\": \\\"/v1/instances/<instance_name>/users/1/\\\",\\n            \\\"self\\\": \\\"/v1/instances/<instance_name>/classes/user_profile/objects/1/\\\"\\n        },\\n        \\\"group_permissions\\\": \\\"none\\\",\\n        \\\"created_at\\\": \\\"2016-06-20T08:43:27.204105Z\\\",\\n        \\\"owner_permissions\\\": \\\"full\\\",\\n        \\\"updated_at\\\": \\\"2016-06-20T08:43:27.204122Z\\\",\\n        \\\"other_permissions\\\": \\\"none\\\",\\n        \\\"owner\\\": 1,\\n        \\\"age\\\": null,\\n        \\\"nickname\\\": null,\\n        \\\"id\\\": 1,\\n        \\\"channel\\\": null,\\n        \\\"revision\\\": 1\\n    },\\n    \\\"links\\\": {\\n        \\\"profile\\\": \\\"/v1/instances/<instance_name>/classes/user_profile/objects/1/\\\",\\n        \\\"self\\\": \\\"/v1/instances/<instance_name>/users/1/\\\",\\n        \\\"groups\\\": \\\"/v1/instances/<instance_name>/users/1/groups/\\\",\\n        \\\"reset-key\\\": \\\"/v1/instances/<instance_name>/users/1/reset_key/\\\"\\n    },\\n    \\\"user_key\\\": \\\"15e8b35e1cd9b8abf806f3e932451f2612bf0d20\\\",\\n    \\\"groups\\\": [\\n        {\\n            \\\"description\\\": \\\"\\\",\\n            \\\"id\\\": 1,\\n            \\\"links\\\": {\\n                \\\"self\\\": \\\"/v1/instances/<instance_name>/groups/1/\\\",\\n                \\\"users\\\": \\\"/v1/instances/<instance_name>/groups/1/users/\\\"\\n            },\\n            \\\"label\\\": \\\"main_group\\\"\\n        }\\n    ],\\n    \\\"id\\\": 1\\n}\",\n      \"language\": \"json\",\n      \"name\": \"JSON\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Resetting a User Key\"\n}\n[/block]\n\n### When to reset a User Key\nUsually you would like to reset a User Key in two situations:\n- When the User Key was compromised \n- Username/password combination was compromised in some way. \n\nThe API Key, in most cases is shared publicly, but it's a safe solution - since API Key (with the flag `ignore_acl` set to `false`) cannot modify any User data without a User Key passed together with it. When a User Key gets compromised someone could use it together with publicly known API Key to change/steal user data.\n\n### Why reset a User Key when username/password combination is leaked? \nBecause by knowing username and password, one can obtain User Key through [Users - Log In](http://docs.syncano.com/v0.1.1/docs/user-log-in) endpoint, making it possible to modify/steal user data.\n\nIf for whatever reason your users username, password, or User Key gets leaked ask them to change their password and reset their User Key right away!\n\n### How to reset the User Key:\nThis is how you can reset the User Key by a call to Syncano API:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: <API_KEY>\\\" \\\\\\n-H \\\"Content-Type: application/json\\\" \\\\\\n\\\"https://api.syncano.io/v1.1/instances/<instance_name>/users/<user_id>/reset_key/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar User = connection.User;\\n\\nUser.please().resetKey({instanceName: INSTANCE_NAME, id: 7}).then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"from syncano.models import *\\nimport syncano\\n\\nsyncano.connect(api_key=\\\"ACCOUNT_KEY\\\")\\n\\nthe_user = User.please.get(\\n    instance_name=\\\"INSTANCE_NAME\\\",\\n    id=USER_ID\\n)\\n\\nthe_user.reset_key()\",\n      \"language\": \"python\",\n      \"name\": \"Python\"\n    },\n    {\n      \"code\": \"syncano.setUser(null);\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"\",\n      \"language\": \"objectivec\",\n      \"name\": \"\"\n    },\n    {\n      \"code\": \"\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"//NOT AVAILABLE\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\nThe result will be a User object with an updated `user_key` field.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Social Login\"\n}\n[/block]\nWith syncano you can allow a user to sign in with Facebook or Google.\n\nIf a user signs up for the first time, their account in syncano will be automatically created, if the user already has an account from this social service, the user will just log in.\n\nThe end effect is that, if you provide a valid authorization token, you'll get user data in the same format as you would get with a traditional username/password login.\n\nTo use social login, you first have to set up Oauth2 apps in facebook or google.\n\nThen you have to implement it on the client side, for example by using [hello.js](http://adodson.com/hello.js/). You don't have to pass any secret keys or secret ids to syncano, just an authorization token.\n\nYou can log in by posting:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: API_KEY\\\" \\\\\\n-H \\\"Content-Type: application/json\\\" \\\\\\n-d '{\\\"access_token\\\": \\\"BACKEND_PROVIDER_TOKEN\\\"}' \\\\\\n\\\"https://api.syncano.io/v1.1/instances/<instance>/user/auth/BACKEND_NAME/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\");\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar User = connection.User;\\n\\nvar query = {instanceName: \\\"INSTANCE_NAME\\\", backend: \\\"facebook\\\"};\\nvar credentials = {access_token: \\\"TOKEN\\\"};\\n\\nUser.please().socialLogin(query, credentials).then(callback);\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"User user = new User(SocialAuthBackend.FACEBOOK, socialNetworkAuthToken);\\nResponse<User> response = user.loginSocialUser();\",\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]\nBackend names:\n\n- facebook\n- google-oauth2\n- twitter\n- linkedin\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Learn More\",\n  \"body\": \"For more details about the available methods for users, visit the [Users API reference](http://docs.syncano.com/v0.1.1/docs/users-list) and [User API reference](http://docs.syncano.com/v0.1.1/docs/user-log-in).\"\n}\n[/block]","excerpt":"This section describes management for your application users. After reading it, you will know how to add, register and authenticate users.","slug":"user-management","type":"basic","title":"User management"}

User management

This section describes management for your application users. After reading it, you will know how to add, register and authenticate users.

1. [Creating an API Key with user creation permissions](#creating-an-api-key-with-user-creation-permissions) 2. [Adding a User](#adding-a-user) 3. [User Profiles](#user-profiles) 4. [Updating user profiles](#updating-user-profiles) 5. [Resetting a User Key](#resetting-a-user-key) 6. [User authentication](#user-authentication) 7. [Social Login](#social-login) [block:api-header] { "type": "basic", "title": "Creating an API Key with user creation permissions" } [/block] To be able to register Users you'll have to create an API Key that has `allow_user_create` flag set to `true` (It is possible to create new Users with the Account Key but it's not the recommended solution). [block:image] { "images": [ { "image": [ "https://files.readme.io/6ckpRxxVSlqs9LPlZA4g_Add_API_Key_01.png", "Add_API_Key_01.png", "1277", "665", "#27446f", "" ] } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/s6tbgYiBSFWDvMN9jo0c_Add_API_Key_02.png", "Add_API_Key_02.png", "1679", "872", "#849cb4", "" ] } ] } [/block] Before confirming, in **step 5.**, please change the switch state in `User registration?` line - this way this API Key will be able to add new users to your Syncano Instance. This is an example of such API Key creation call: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: ACCOUNT_KEY\" \\\n-H \"Content-type: application/json\" \\\n-d '{\"allow_user_create\":true}' \\\n\"https://api.syncano.io/v1.1/instances/instance/api_keys/\"", "language": "curl" }, { "code": "from syncano.models import ApiKey\nimport syncano\n\nsyncano.connect(api_key=\"API_KEY\")\n\nnew_key = ApiKey.please.create(\n instance_name=\"INSTANCE_NAME\",\n allow_user_create=True\n)\n", "language": "python" }, { "code": "var Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar ApiKey = connection.ApiKey;\n\nvar options = {\n allow_user_create: true, \n instanceName: \"INSTANCE_NAME\"\n};\n\nApiKey.please().create(options).then(callback);", "language": "javascript" }, { "code": "// Not supported in Android Library - please use Dashboard instead.", "language": "java", "name": "Android" }, { "code": "// Not supported in iOS Library - please use Dashboard instead.", "language": "objectivec" }, { "code": "// Not supported in iOS Library - please use Dashboard instead.", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "// Not supported in Unity Library - please use Dashboard instead.", "language": "csharp", "name": "Unity" } ] } [/block] Example response: [block:code] { "codes": [ { "code": "{\n \"id\": 819, \n \"description\": \"\", \n \"api_key\": \"78997d74c0f71141e489a3284fb4f2e464abdc19\", \n \"ignore_acl\": false, \n \"allow_user_create\": true, \n \"created_at\": \"2015-04-21T14:19:41.309520Z\", \n \"links\": {\n \"self\": \"/v1.1/instances/<instance>/api_keys/819/\", \n \"reset_key\": \"/v1.1/instances/<instance>/api_keys/819/reset_key/\"\n }\n}", "language": "json" } ] } [/block] Now we can utilize this API Key in the `User add` API call: [block:api-header] { "type": "basic", "title": "Adding a User" } [/block] Once we create the API Key with `allow_user_create` flag set to true (mentioned in a previous [section](#creating-an-api-key-with-user-creation-permissions)) adding new users is pretty straightforward. Go to `Users & Groups` tab in the Dashboard's Navigation Bar. [block:image] { "images": [ { "image": [ "https://files.readme.io/HGf24vCwSZe83baXV9Rb_Add_user_01.png", "Add_user_01.png", "1679", "736", "#254472", "" ] } ] } [/block] When you click `Create a User` button, you will see a pop-up. Type there new user `username` and `password` and press `Confirm` to save. [block:image] { "images": [ { "image": [ "https://files.readme.io/tVUevONOSmGUXOYlnPqV_Add_user_02.png", "Add_user_02.png", "1679", "773", "#254474", "" ] } ] } [/block] For adding new user in code, please see the example below: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: API_KEY_WITH_ALLOW_USER_CREATE_FLAG\" \\\n-H \"Content-type: application/json\" \\\n-d '{\"username\":\"Gordon Freeman\",\"password\":\"Black Mesa\"}' \\\n\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/users/\"", "language": "curl" }, { "code": "from syncano.models import User\nimport syncano\n\nsyncano.connect(api_key=\"API_KEY_WITH_ALLOW_USER_CREATE_FLAG\") \n# You can use an account key as well\n\nGordon = User.please.create(\n instance_name=\"INSTANCE_NAME\",\n username=\"Gordon Freeman\",\n password=\"Black Mesa\"\n)", "language": "python" }, { "code": "var Syncano = require(\"syncano\");\nvar connection = Syncano({apiKey: API_KEY_WITH_ALLOW_USER_CREATE_FLAG});\nvar User = connection.User;\n\nvar options = {\n username: USERNAME, \n password: PASSWORD,\n instanceName: INSTANCE_NAME\n};\n\nUser.please().create(options).then(callback);", "language": "javascript" }, { "code": "User newUser = new User(userName, password);\nResponse<User> response = newUser.register();", "language": "java", "name": "Android" }, { "code": "[Syncano sharedInstanceWithApiKey:@\"API_KEY\" instanceName:@\"instance_name\"];\n[SCUser registerWithUsername:username password:password completion:^(NSError *error) {\n //handle user registration\n}];", "language": "objectivec" }, { "code": "Syncano.sharedInstanceWithApiKey(\"API_KEY\", instanceName: \"instance_name\")\nSCUser.registerWithUsername(username, password: password) { error in\n //handle error\n}", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "User<Profile> user = new User<Profile>(\"username\", \"password\");\nuser.Register(UserCreateCallback);", "language": "csharp", "name": "Unity" } ] } [/block] Example response: [block:code] { "codes": [ { "code": "{\n \"id\": 66, \n \"username\": \"Gordon Freeman\", \n \"user_key\": \"33b966b883351528e4ee3206cd84bd42fcf2d4a4\", \n \"profile\": {\n \"id\": 1198, \n \"created_at\": \"2015-03-25T14:01:31.962783Z\", \n \"updated_at\": \"2015-03-25T14:01:31.962810Z\", \n \"revision\": 1, \n \"owner\": 66, \n \"owner_permissions\": \"full\", \n \"group\": null, \n \"group_permissions\": \"none\", \n \"other_permissions\": \"none\", \n \"channel\": null, \n \"channel_room\": null, \n \"links\": {\n \"owner\": \"/v1.1/instances/<instance>/users/66/\", \n \"self\": \"/v1.1/instances/<instance>/classes/user_profile/objects/1198/\"\n }\n }, \n \"links\": {\n \"self\": \"/v1.1/instances/<instance>/users/66/\", \n \"reset-key\": \"/v1.1/instances/<instance>/users/66/reset_key/\", \n \"groups\": \"/v1.1/instances/<instance>/users/66/groups/\"\n }\n}", "language": "json" } ] } [/block] Whoa! Quite a lot of info in this User object! Let's break it down, so that it's a bit easier to digest. If we omit the `profile` property(we'll get back to it in a moment), this is how User object looks like: [block:code] { "codes": [ { "code": "{\n \"id\": 66, \n \"username\": \"Gordon Freeman\", \n \"user_key\": \"33b966b883351528e4ee3206cd84bd42fcf2d4a4\", \n \"profile\": {...}, \n \"links\": {...}\n}", "language": "json" } ] } [/block] Ok, so this is a bit simpler. What we've got here is: [block:parameters] { "data": { "0-0": "id", "h-0": "Property", "h-1": "Description", "0-1": "User id", "1-0": "username", "1-1": "Name of the user that was provided during registration", "2-0": "user_key", "2-1": "User authentication key. Should be used when making calls to the `/user` endpoint", "3-0": "profile", "3-1": "User profile object", "4-0": "links", "4-1": "HATEOAS links to connected resources" }, "cols": 2, "rows": 5 } [/block] At this point you might probably ask "Ok, wait a sec! What exactly is this `profile` thing?". We'll explain it in the next section which is called (you'll never guess)... [block:api-header] { "type": "basic", "title": "User Profiles" } [/block] As you may have noticed when browsing through the API or Admin GUI, there's an extra default Data Class sitting in each Instance that you create. This Data Class, called "user_profile", stores Data Objects, which are the profiles of your Users. So, whenever a new User is added, a special "profile" Data Object is being created. The user_profile Data Class and its Data Objects profiles are protected, which means that no one can delete the user_profile Data Class, create new user profiles manually, delete profiles, or change ownership of the profile (user is always their profile owner). ### Why should I care? Excellent question! Since user profiles are just Data Objects stored in a Data Class, you can simply change this Data Class Schema to add custom fields. ### Example Let's say you'd like your users to have the ability to add profile pictures. What we'll do, is change the 'user_profile' Data Class to have an 'avatar' field. [block:callout] { "type": "info", "body": "If you'd like a reminder of what Data Class or Data Class Schema is, please see [this chapter](http://docs.syncano.io/docs/classes-overview)." } [/block] 1. Go to Data Classes Tab in the [Dashboard](https://dashboard.syncano.io). As you see, `user_profile` data class is already there, no need to create it. To edit this data class, click on dropdown icon. [block:image] { "images": [ { "image": [ "https://files.readme.io/O2pIv4ctSCyk17goajbS_Edit_user_profile_01.png", "Edit_user_profile_01.png", "1679", "767", "#264471", "" ] } ] } [/block] Choose `Edit a Data Class` option from the dropdown. [block:image] { "images": [ { "image": [ "https://files.readme.io/8G01qSnQGWMP23XXgKCj_Edit_user_profile_02.png", "Edit_user_profile_02.png", "1679", "770", "#254473", "" ] } ] } [/block] Enter new field name and type (in our example it would be `avatar` field of type `file`) and click `ADD` next to it. Press `Update` to save changes. [block:image] { "images": [ { "image": [ "https://files.readme.io/44d3eb7-update_class.png", "update_class.png", 1924, 1532, "#f8f8f2" ] } ] } [/block] You can make same kind of changes to `user_profile` data class, using our API: [block:code] { "codes": [ { "code": "curl -X PATCH \\\n-H \"X-API-KEY: ACCOUNT_KEY\" \\\n-d schema='[{\"name\":\"avatar\",\"type\":\"file\"}]' \\\n\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/classes/user_profile/\"", "language": "curl" }, { "code": "import syncano \n\nconnection = syncano.connect('ACCOUNT_KEY')\n\nClass = connection.Class\n\nuser_profile_class = Class.please.get(\n instance_name='instance_name',\n name='user_profile'\n)\n\nuser_profile_class.schema.add({\"name\": \"avatar\", \"type\": \"file\"})\nuser_profile_class.save()", "language": "python" }, { "code": "var Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar Class = connection.Class;\n\nvar query = {\n\tinstanceName: \"INSTANCE_NAME\",\n className: \"user_profile\"\n};\n\nvar update = {\n\tschema : [{\"name\":\"avatar\",\"type\":\"file\"}]\n};\n\nClass.please().update(query, update).then(callback);", "language": "javascript" }, { "code": "// MyUserProfile should extend Profile class\nResponse<SyncanoClass> response = syncano.updateSyncanoClass(MyUserProfile.class).send();", "language": "java", "name": "Android" }, { "code": "// You cannot change class schema from iOS, but it's really easy to do using our Dashboard!", "language": "objectivec" }, { "code": "// You cannot change class schema from iOS, but it's really easy to do using our Dashboard!", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" } ] } [/block] Now a user has an extra `avatar` field in their user profile, which the user can update with an avatar picture: [block:code] { "codes": [ { "code": "curl -X PATCH \\\n-H \"X-API-KEY: API_KEY\" \\\n-H \"X-USER-KEY: USER_KEY\n-H \"Content-type:multipart/form-data\" \\\n-F name=\"avatar\" \\\n-F filename=@user_avatar_file \\\n-k \"https://api.syncano.io/v1.1/instances/instance/classes/user_profile/objects/4328/\"", "language": "curl" }, { "code": "import syncano\nfrom syncano.models import Object\n\nconnection = syncano.connect(api_key='API_KEY')\n\nimage_path = \"/sample_path/user_avatar.jpg\"\navatar= open(image_path, \"r\")\n\nObject.please.update(\n \tid=ID\n instance_name=\"INSTANCE_NAME\",\n class_name=\"CLASS_NAME\",\n avatar=avatar\n)", "language": "python" }, { "code": "var fs = require(\"fs\");\nvar Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar DataObject = connection.DataObject;\n\nvar object = {\n id: ID\n avatar: Syncano.file(fs.readFileSync('/sample_path/user_avatar.jpg')),\n instanceName: \"INSTANCE_NAME\",\n className: \"CLASS_NAME\"\n};\n\nDataObject.please().update(object).then(callback);", "language": "javascript" }, { "code": "MyUserProfile profile = user.getProfile();\nprofile.avatar = new SyncanoFile(new File(getAssetsDir(), \"blue.png\"));\nResponse<MyUserProfile> responseAvatar = profile.save();", "language": "java", "name": "Android" }, { "code": "@interface MyUserProfile : SCUserProfile\n@property (nonatomic, strong) SCFile *avatar;\n@end\n\n@interface MyUser : SCUser\n@property (nonatomic,retain) MyUserProfile *profile;\n@end\n\n@implementation MyUserProfile\n@end\n \n@implementation MyUser\n@dynamic profile;\n@end\n \n[Syncano sharedInstanceWithApiKey:@\"API_KEY\" instanceName:@\"instance_name\"];\n//call this once, before you interact with Syncano in any way\n[MyUser registerClassWithProfileClass:[MyUserProfile class]];\n//now it's safe to use custom profiles\nMyUser *currentUser = [MyUser currentUser];\nMyUserProfile *profile = currentUser.profile;\nprofile.avatar = [SCFile fileWithaData:UIImageJPEGRepresentation([UIImage imageNamed:@\"imageName\"], 0.7)];\n[profile saveWithCompletionBlock:^(NSError *error) {\n //handle error\n}];", "language": "objectivec" }, { "code": "class MyUserProfile : SCUserProfile {\n var avatar : SCFile? = nil;\n}\n\nclass MyUser : SCUser {\n var myProfile : MyUserProfile? {\n get {\n return profile as? MyUserProfile\n }\n set {\n profile = newValue\n }\n }\n}\n\nSyncano.sharedInstanceWithApiKey(\"API_KEY\", instanceName: \"instance_name\")\n//call this once, before you interact with Syncano in any way\nMyUser.registerClassWithProfileClass(MyUserProfile.self)\n//now it's safe to use custom profiles\nlet currentUser = MyUser.currentUser()\nlet profile = currentUser.myProfile\nprofile?.avatar = SCFile(withaData: UIImageJPEGRepresentation(UIImage(named: \"imageName\")!, 0.7))\nprofile?.saveWithCompletionBlock() { error in\n //handle error\n}", "language": "objectivec", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "User<TestProfile> user = new User<TestProfile>(\"username\", \"password\");\n\nyield return user.Login(UserCallbackSuccess, UserCallbackFail); //Wait until we successfully login.\n\nSyncanoFile avatar = new SyncanoFile(AvatarImage.sprite.texture.EncodeToPNG());\n\nuser.Profile = new TestProfile(avatar);\nuser.UpdateCustomUser(UserCallbackSuccess, UserCallbackFail);", "language": "csharp", "name": "Unity" } ] } [/block] And voila! The User profile just got a new shiny avatar image: [block:code] { "codes": [ { "code": "{\n \"id\": 4328, \n \"created_at\": \"2015-04-21T11:31:54.249412Z\", \n \"updated_at\": \"2015-04-23T14:11:26.603282Z\", \n \"revision\": 7, \n \"owner\": 1429, \n \"owner_permissions\": \"none\", \n \"group\": null, \n \"group_permissions\": \"none\", \n \"other_permissions\": \"none\", \n \"channel\": null, \n \"channel_room\": null, \n \"avatar\": {\n \"type\": \"file\", \n \"value\": \"https://api.syncano.io.s3.amazonaws.com/1/5/7aecf4b79f8f033caf9cc2619ee4d14e6bda8832.jpg\"\n }, \n \"links\": {...}\n}", "language": "json" } ] } [/block] [block:api-header] { "type": "basic", "title": "User authentication" } [/block] [block:callout] { "type": "warning", "body": "To authenticate a user, you'll need to make a call to the `/user/` endpoint. This endpoint is unique in terms of authentication because to get or update the user details you will need to use a combination of an api_key and user_key.\n\naccount_key will not work in this endpoint!", "title": "Important!" } [/block] User authentication is used when we want our users to be able to login to our application. For a successful User auth call we need user credentials (login and password) and an API Key. Here is an example of such call: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: API_KEY\" \\\n-H \"Content-type: application/json\" \\\n-d '{\"username\":\"Gordon Freeman\",\"password\":\"Black mesa\"}' \\\n\"https://api.syncano.io/v1.1/instances/INSTANCE_NAME/user/auth/\"", "language": "curl" }, { "code": "import syncano\n\nsyncano.connect(\n api_key=\"API_KEY\",\n instance_name=\"INSTANCE_NAME\",\n username=\"Gordon Freeman\",\n password=\"Black Mesa\"\n)", "language": "python" }, { "code": "var Syncano = require(\"syncano\");\nvar connection = Syncano({apiKey: \"API_KEY\"});\nvar User = connection.User;\n\nvar query = {instanceName: \"INSTANCE_NAME\"};\nvar credentials = {username: \"EMAIL\", password: \"PASSWORD\"};\n\nUser.please().login(query, credentials).then(function(res) {\n // userKey will be saved in a connection object and can be used\n // in further calls\n console.log(connection.userKey);\n});", "language": "javascript" }, { "code": "User plainUser = new User(userName, password);\n\nResponse<User> response = plainUser.on(userSyncano).login();\n// All next requests will be used using apiKey and userKey.", "language": "java", "name": "Android" }, { "code": "[Syncano sharedInstanceWithApiKey:@\"API_KEY\" instanceName:@\"instance_name\"];\n[SCUser loginWithUsername:username password:password completion:^(NSError *error) {\n //handle error\n}];", "language": "objectivec" }, { "code": "Syncano.sharedInstanceWithApiKey(\"API_KEY\", instanceName: \"instance_name\")\nSCUser.loginWithUsername(\"username\", password: \"password\") { error in\n //handle error\n}", "language": "javascript", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "User<Profile> user = new User<Profile>(\"username\", \"password\");\nuser.Login(UserCreateCallbackSuccess, UserCreateCallbackFail);", "language": "csharp", "name": "Unity" } ] } [/block] User login call returns `user_key` in the response: [block:code] { "codes": [ { "code": "{\n \"id\": 66, \n \"username\": \"Gordon Freeman\", \n \"user_key\": \"33b966b883351528e4ee3206cd84bd42fcf2d4a4\", \n \"profile\": {...}, \n \"links\": {...}\n}", "language": "json" } ] } [/block] [block:callout] { "type": "success", "body": "`user_key` should be used along with `api_key` in all subsequent calls on the client side. So i.e. a call where a user is creating a Data Object would look like this:" } [/block] [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 '{\"name\": \"I am an object name\"}' \\\n\"https://api.syncano.io/v1.1/instances/instance_name/classes/class/objects/\"", "language": "curl" }, { "code": "from syncano.models import Object\nimport syncano\n\nsyncano.connect(\n api_key=\"API_KEY\",\n user_key=\"USER_KEY\",\n instance_name=\"INSTANCE_NAME\"\n)\n\nObject.please.create(\n instance_name=\"INSTANCE_NAME\",\n class_name=\"CLASS_NAME\",\n name=\"I am a data object\"\n)\n", "language": "python" }, { "code": "var Syncano = require(\"syncano\");\nvar connection = Syncano({apiKey: \"API_KEY\", userKey: \"USER_KEY\"});\nvar DataObject = connection.DataObject;\n\nvar object = {\n instanceName: \"INSTANCE_NAME\", \n className: \"CLASS_NAME\",\n\tname: \"I am an object name\"\n};\n\nDataObject.please().create(object).then(callback);", "language": "javascript" }, { "code": "syncano.setUserKey(userKey);", "language": "java", "name": "Android" }, { "code": "// In iOS you don't need to extract User Key manually - after logging in it will be used automatically\n\n[Syncano sharedInstanceWithApiKey:@\"API_KEY\" instanceName:@\"instance_name\"];\n[SCUser loginWithUsername:username password:password completion:^(NSError *error) {\n Book *book = [Book new];\n book.title = @\"The Last Wish\";\n //this call will be made with User Key\n [book saveWithCompletionBlock:^(NSError *error) {\n }];\n}];", "language": "objectivec" }, { "code": "// In iOS you don't need to extract User Key manually - after logging in it will be used automatically\n\nSyncano.sharedInstanceWithApiKey(\"API_KEY\", instanceName: \"instance_name\")\nSCUser.loginWithUsername(\"username\", password: \"password\") { error in\n //handle error\n let book = Book()\n book.title = \"The Last Wish\"\n //this call will be made with User Key\n book.saveWithCompletionBlock { error in\n }\n}", "language": "javascript", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "// NOT AVAILABLE", "language": "csharp", "name": "Unity" } ] } [/block] The `user_key` can be used for a prolonged period of time, because it expires only in the event of user changing his password. This way it is possible to store it within your application without the need to store the user’s password itself. [block:api-header] { "type": "basic", "title": "Updating user profiles" } [/block] There are three ways to update user profiles. You can do this manually by Syncano Dashboard and by endpoints. ##Updating by user end-point For updating specified user profile you need to use your API Key and User Key. You can see the example below: [block:code] { "codes": [ { "code": "curl -X PATCH \\\n-H \"X-API-KEY: <API_KEY>\" \\\n-H \"X-USER-KEY: <USER_KEY>\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\"username\":\"<new_username>\",\n\t \"password\":\"<new_password>\"}' \\\n\"https://api.syncano.io/v1/instances/<instance_name>/user/\" ", "language": "curl", "name": "cURL" }, { "code": "var Syncano = require('syncano'); //CommonJS\nvar instance = Syncano({instance: 'INSTANCE_NAME', apiKey: 'API_KEY', userKey: 'USER_KEY'});\n\nvar user = {\n \"username\":\"<new_username>\", \n \"password\":\"<new_password>\"\n};\n\ninstance.user().update(user, callback());", "language": "javascript", "name": "JavaScript" } ] } [/block] You don't need to update all user parameters. You can update only one of them. Example response: [block:code] { "codes": [ { "code": "{\n \"username\": \"sample_username\",\n \"profile\": {\n \"channel_room\": null,\n \"group\": null,\n \"links\": {\n \"owner\": \"/v1/instances/rivia/users/1/\",\n \"self\": \"/v1/instances/rivia/classes/user_profile/objects/1/\"\n },\n \"group_permissions\": \"none\",\n \"created_at\": \"2016-06-20T08:43:27.204105Z\",\n \"owner_permissions\": \"full\",\n \"updated_at\": \"2016-06-20T08:43:27.204122Z\",\n \"other_permissions\": \"none\",\n \"owner\": 1,\n \"age\": null,\n \"nickname\": null,\n \"id\": 1,\n \"channel\": null,\n \"revision\": 1\n },\n \"links\": {\n \"profile\": \"/v1/instances/rivia/classes/user_profile/objects/1/\",\n \"self\": \"/v1/instances/rivia/users/1/\",\n \"groups\": \"/v1/instances/rivia/users/1/groups/\",\n \"reset-key\": \"/v1/instances/rivia/users/1/reset_key/\"\n },\n \"user_key\": \"15e5b35e1cd8s8abf806f3e925951f2612bf0d20\",\n \"groups\": [\n {\n \"description\": \"\",\n \"id\": 1,\n \"links\": {\n \"self\": \"/v1/instances/rivia/groups/1/\",\n \"users\": \"/v1/instances/rivia/groups/1/users/\"\n },\n \"label\": \"main_group\"\n }\n ],\n \"id\": 1\n}", "language": "json", "name": null } ] } [/block] ##Updating by users end-point Second way to update user profile is to use `users end-point` as the sample below. In this case you need only API Key and user id. [block:code] { "codes": [ { "code": "curl -X PATCH \\\n-H \"X-API-KEY: <API_KEY>\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\"username\":\"<new_username>\",\n \"password\":\"<new_password>\"}' \\\n\"https://api.syncano.io/v1/instances/<instance_name>/users/<user_id>/\"", "language": "curl", "name": "cURL" }, { "code": "from syncano.models import User\nimport syncano\n\nsyncano.connect(api_key=\"API_KEY\")\n\nUser.please.update(instance_name=\"INSTANCE_NAME\",\n ID=USER_ID,\n username=\"NEW_USERNAME\",\n password=\"NEW_PASSWORD\")", "language": "python", "name": "Python" }, { "code": "var Syncano = require(\"syncano\");\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar User = connection.User;\n\nvar query = {instanceName: INSTANCE_NAME, id: USER_ID};\nvar update = {username: USERNAME, password: PASSWORD};\n\nUser.please().update(query, update).then(callback);", "language": "javascript", "name": "JavaScript" } ] } [/block] Example response: [block:code] { "codes": [ { "code": "{\n \"username\": \"another_username\",\n \"profile\": {\n \"channel_room\": null,\n \"group\": null,\n \"links\": {\n \"owner\": \"/v1/instances/<instance_name>/users/1/\",\n \"self\": \"/v1/instances/<instance_name>/classes/user_profile/objects/1/\"\n },\n \"group_permissions\": \"none\",\n \"created_at\": \"2016-06-20T08:43:27.204105Z\",\n \"owner_permissions\": \"full\",\n \"updated_at\": \"2016-06-20T08:43:27.204122Z\",\n \"other_permissions\": \"none\",\n \"owner\": 1,\n \"age\": null,\n \"nickname\": null,\n \"id\": 1,\n \"channel\": null,\n \"revision\": 1\n },\n \"links\": {\n \"profile\": \"/v1/instances/<instance_name>/classes/user_profile/objects/1/\",\n \"self\": \"/v1/instances/<instance_name>/users/1/\",\n \"groups\": \"/v1/instances/<instance_name>/users/1/groups/\",\n \"reset-key\": \"/v1/instances/<instance_name>/users/1/reset_key/\"\n },\n \"user_key\": \"15e8b35e1cd9b8abf806f3e932451f2612bf0d20\",\n \"groups\": [\n {\n \"description\": \"\",\n \"id\": 1,\n \"links\": {\n \"self\": \"/v1/instances/<instance_name>/groups/1/\",\n \"users\": \"/v1/instances/<instance_name>/groups/1/users/\"\n },\n \"label\": \"main_group\"\n }\n ],\n \"id\": 1\n}", "language": "json", "name": "JSON" } ] } [/block] [block:api-header] { "type": "basic", "title": "Resetting a User Key" } [/block] ### When to reset a User Key Usually you would like to reset a User Key in two situations: - When the User Key was compromised - Username/password combination was compromised in some way. The API Key, in most cases is shared publicly, but it's a safe solution - since API Key (with the flag `ignore_acl` set to `false`) cannot modify any User data without a User Key passed together with it. When a User Key gets compromised someone could use it together with publicly known API Key to change/steal user data. ### Why reset a User Key when username/password combination is leaked? Because by knowing username and password, one can obtain User Key through [Users - Log In](http://docs.syncano.com/v0.1.1/docs/user-log-in) endpoint, making it possible to modify/steal user data. If for whatever reason your users username, password, or User Key gets leaked ask them to change their password and reset their User Key right away! ### How to reset the User Key: This is how you can reset the User Key by a call to Syncano API: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: <API_KEY>\" \\\n-H \"Content-Type: application/json\" \\\n\"https://api.syncano.io/v1.1/instances/<instance_name>/users/<user_id>/reset_key/\"", "language": "curl" }, { "code": "var Syncano = require(\"syncano\");\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar User = connection.User;\n\nUser.please().resetKey({instanceName: INSTANCE_NAME, id: 7}).then(callback);", "language": "javascript" }, { "code": "from syncano.models import *\nimport syncano\n\nsyncano.connect(api_key=\"ACCOUNT_KEY\")\n\nthe_user = User.please.get(\n instance_name=\"INSTANCE_NAME\",\n id=USER_ID\n)\n\nthe_user.reset_key()", "language": "python", "name": "Python" }, { "code": "syncano.setUser(null);", "language": "java", "name": "Android" }, { "code": "", "language": "objectivec", "name": "" }, { "code": "", "language": "objectivec", "name": "Swift" }, { "code": "//NOT AVAILABLE", "language": "csharp", "name": "Unity" } ] } [/block] The result will be a User object with an updated `user_key` field. [block:api-header] { "type": "basic", "title": "Social Login" } [/block] With syncano you can allow a user to sign in with Facebook or Google. If a user signs up for the first time, their account in syncano will be automatically created, if the user already has an account from this social service, the user will just log in. The end effect is that, if you provide a valid authorization token, you'll get user data in the same format as you would get with a traditional username/password login. To use social login, you first have to set up Oauth2 apps in facebook or google. Then you have to implement it on the client side, for example by using [hello.js](http://adodson.com/hello.js/). You don't have to pass any secret keys or secret ids to syncano, just an authorization token. You can log in by posting: [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: API_KEY\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\"access_token\": \"BACKEND_PROVIDER_TOKEN\"}' \\\n\"https://api.syncano.io/v1.1/instances/<instance>/user/auth/BACKEND_NAME/\"", "language": "curl" }, { "code": "# Coming soon!", "language": "python" }, { "code": "var Syncano = require(\"syncano\");\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar User = connection.User;\n\nvar query = {instanceName: \"INSTANCE_NAME\", backend: \"facebook\"};\nvar credentials = {access_token: \"TOKEN\"};\n\nUser.please().socialLogin(query, credentials).then(callback);", "language": "javascript" }, { "code": "User user = new User(SocialAuthBackend.FACEBOOK, socialNetworkAuthToken);\nResponse<User> response = user.loginSocialUser();", "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] Backend names: - facebook - google-oauth2 - twitter - linkedin [block:callout] { "type": "info", "title": "Learn More", "body": "For more details about the available methods for users, visit the [Users API reference](http://docs.syncano.com/v0.1.1/docs/users-list) and [User API reference](http://docs.syncano.com/v0.1.1/docs/user-log-in)." } [/block]