{"_id":"56138c7a6fd7042b008f0187","project":"55edea207145f717001ac12c","user":"55ede9ed1452cd0d009e5e6b","__v":4,"category":{"_id":"55ffceca0e2b090d008633b2","pages":["55ffcedffeaf310d007dd6d6","55ffd0879e7ccf0d000a1e09","55ffddd1feaf310d007dd6e8","55ffdee4feaf310d007dd6ea","55ffe2336932a00d00ba7abf","55ffeb898c0c9d0d00dcacd0","55fff74c6932a00d00ba7b0c","55fff9df0c703d1900952fe1","55fffecb6932a00d00ba7b1b","55ffffd49e7ccf0d000a1e49","560001159e7ccf0d000a1e4d","560004126932a00d00ba7b2a","560006ef0c703d1900952ffc","560009fa8c0c9d0d00dcad0d","5601137f9137690d00335697","560120f34ea1b40d003bf1a4","5601221bf01fb90d00d4bf7e","5601274781a9670d006d1514","5601292881a9670d006d1516","56012ab3f01fb90d00d4bf88","56012c754ea1b40d003bf1b9","56012d824ea1b40d003bf1c0","56053e9df6b86e0d00284ad1","560541907c8e580d0001afe8","56123c063cf4bc0d00554e37","561264c70157131900b45863","561272d60157131900b45870","5612796d09bdc51700696fdf","56138c7a6fd7042b008f0187","5613a63d46c35f3500773c06","5613a79a44d6662b0071f5d9"],"project":"55edea207145f717001ac12c","version":"55edea207145f717001ac12f","__v":31,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-09-21T09:32:58.200Z","from_sync":false,"order":0,"slug":"sdk","title":"SDK"},"version":{"_id":"55edea207145f717001ac12f","project":"55edea207145f717001ac12c","__v":11,"createdAt":"2015-09-07T19:48:48.670Z","releaseDate":"2015-09-07T19:48:48.670Z","categories":["55edea217145f717001ac130","55ffa8038c0c9d0d00dcac72","55ffbaa48c0c9d0d00dcac88","55ffbd3e8c0c9d0d00dcac8b","55ffbee40e2b090d00863393","55ffc4306932a00d00ba7a85","55ffc66bfeaf310d007dd6c8","55ffc9c2feaf310d007dd6d1","55ffceca0e2b090d008633b2","560111b06811d00d00ceb34e","560262e74f15002100ee4445"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-10-06T08:55:22.055Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":33,"body":"##Getting list of active features\nDeveloper can obtain the list of active features for current integration using the following code.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<?\\ntry {\\n    $client = new RublonAPIGetAvailableFeatures($rublon); // Pass the Rublon2Factor instance.\\n    $client->perform();\\n\\n    // Here is the list of features:\\n    $features = $client->getFeatures();\\n\\n    // You can check a signle feature:\\n    $isRemoteLogoutAvailable = !empty($features[RublonAPIGetAvailableFeatures::FEATURE_REMOTE_LOGOUT]);\\n\\n} catch (RublonException $e) {\\n    die($e->getMessage());\\n}\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"try \\n{\\n    GetAvailableFeatures client = new GetAvailableFeatures(rublon); // Pass the Rublon2Factor instance.\\n    client.Perform();\\n\\n    // Here is the list of features:\\n    JObject features = client.GetFeatures();\\n\\n    // You can check a signle feature:\\n    bool isRemoteLogoutAvailable = features.Value<bool>(GetAvailableFeatures.FEATURE_REMOTE_LOGOUT);\\n} \\ncatch (RublonException ex) \\n{\\n    // handle errors\\n}\",\n      \"language\": \"csharp\",\n      \"name\": \".NET\"\n    },\n    {\n      \"code\": \"try {\\n\\n  GetAvailableFeatures client = new GetAvailableFeatures(rublon); // Pass the Rublon2Factor instance.\\n  client.perform();\\n\\n  // Here is the list of features:\\n  JSONObject features = client.getFeatures();\\n\\n  // You can check a signle feature:\\n  boolean isRemoteLogoutAvailable = features.optBoolean(GetAvailableFeatures.FEATURE_REMOTE_LOGOUT, false);\\n\\n} catch (RublonException e) {\\n  // handle errors\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n##Confirmations\n\nThe [Secure transaction confirmation](doc:sdk-secure-transaction-confirmation) described in this document is an extra feature.\n\n##Force mobile app\n\nDeveloper can force users to authenticate by Rublon mobile app and deny access to users that are using the Email2FA. This will increase the security level, but also requires users to own a smartphone and install the Rublon application.\n\nTo achieve this you have to pass the additional parameter in the `consumerParams` array during the initiation of the authentication process:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<?\\n$url = $rublon->auth(\\n    $callbackUrl = \\\"http://example.com/rublon_callback.php\\\",\\n    $_SESSION[\\\"user\\\"][\\\"id\\\"], // User Id\\n    $_SESSION[\\\"user\\\"][\\\"email\\\"], // User email\\n    $params = array(\\n        **RublonAuthParams::FIELD_FORCE_MOBILE_APP => true,**\\n    )\\n);\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"User user = (User)Session[\\\"loggedUser\\\"];\\nJObject parameters = new JObject();\\nparameters.Add(RublonAuthParams.FIELD_FORCE_MOBILE_APP, true);\\n    \\nstring url = rublon.Authorize\\n(\\n    \\\"http://example.com/RublonCallback\\\", // callback URL\\n    user.Id, // User Id\\n    user.Email, // User email\\n    parameters\\n);\",\n      \"language\": \"csharp\",\n      \"name\": \".NET\"\n    },\n    {\n      \"code\": \"String url = rublon.auth(\\n  \\\"http://example.com/rublon_callback\\\", // callback URL\\n  Session.getUser().getId(), // User Id\\n  Session.getUser().getEmail(), // User email\\n  new JSONObject() {{\\n    **put(RublonAuthParams.FIELD_FORCE_MOBILE_APP, true);**\\n  }}\\n);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nYou can just imagine a lot of use cases for this feature. For example, the Wordpress administrator which have installed the WP plugin (provided by us) can force choosen users' roles to authenticate using Rublon mobile app.\n\n##Ignore Trusted Device\n\nYou can increase the security level in some cases, for example when user didn't login for last 30 days, by ignoring his Trusted Device during the Rublon authentication. Even if user's Trusted Device exists, he will be forced to scan the QR code.\n\nTo achieve this you have to pass the additional parameter in the `consumerParams` array during the initiation of the authentication process:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<?\\n$url = $rublon->auth(\\n    $callbackUrl = \\\"http://example.com/rublon_callback.php\\\",\\n    $_SESSION[\\\"user\\\"][\\\"id\\\"], // User Id\\n    $_SESSION[\\\"user\\\"][\\\"email\\\"], // User email\\n    $params = array(\\n        **RublonAuthParams::FIELD_IGNORE_TRUSTED_DEVICE => true,**\\n    )\\n);\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"User user = (User)Session[\\\"loggedUser\\\"];\\nJObject parameters = new JObject();\\nparameters.Add(RublonAuthParams.FIELD_IGNORE_TRUSTED_DEVICE, true);\\n    \\nstring url = rublon.Authorize\\n(\\n    \\\"http://example.com/RublonCallback\\\", // callback URL\\n    user.Id, // User Id\\n    user.Email, // User email\\n    parameters\\n);\",\n      \"language\": \"csharp\",\n      \"name\": \".NET\"\n    },\n    {\n      \"code\": \"String url = rublon.auth(\\n  \\\"http://example.com/rublon_callback\\\", // callback URL\\n  Session.getUser().getId(), // User Id\\n  Session.getUser().getEmail(), // User email\\n  new JSONObject() {{\\n    **put(RublonAuthParams.FIELD_IGNORE_TRUSTED_DEVICE, true);**\\n  }}\\n);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n##Buffered confirmation\n\nIf you want to make life easier for your users and don't need extra high security level when users perform the multiple confirmations in a small amount of time, you can use the buffered confirmations feature.\n\nUser will be required to confirm the first confirmation using the Rublon mobile app or clicking the confirmation link sent to his email address (when using Email2FA). Developer determines a time buffer withing the next user's confirmation will be accepted immediately, without the need to use the mobile app or checking the email. The only requirement is that the user's Trusted Device has to be present before performing the confirmation. Without a Trusted Device every transaction have to be confirmed manually.\n\nThe following code shows how to determine the time buffer (in seconds) during the confirmation transaction initiation:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<?\\n$url = $rublon->confirm(\\n    $callbackUrl = \\\"http://example.com/rublon_transaction_confirm.php\\\",\\n    $user[\\\"id\\\"], // User Id\\n    $user[\\\"email\\\"], // User email\\n    $msg = sprintf(\\\"Do you confirm transaction no. %d with the amount of %d?\\\", $transId, $amount),\\n    $params = array(\\n        \\\"transId\\\" => $transId, // Additional transaction parameters\\n        RublonAuthParams::FIELD_CONFIRM_TIME_BUFFER => 300, // 5 minutes\\n    )\\n);\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"User user = (User)Session[\\\"loggedUser\\\"];\\nJObject parameters = new JObject();\\nparameters.Add(\\\"transId\\\", transId); \\nparameters.Add(RublonAuthParams.FIELD_CONFIRM_TIME_BUFFER, 300); // 5 minutes\\n\\nstring url = rublon.Confirm\\n(\\n    \\\"http://example.com/TransactionConfirmCallback\\\", // callback URL\\n    user.Id, // User Id\\n    user.Email, // User email\\n    string.format(\\\"Do you confirm transaction no. {0} with the amount of {1}?\\\", transId, amount),\\n    parameters\\n);\",\n      \"language\": \"csharp\",\n      \"name\": \".NET\"\n    },\n    {\n      \"code\": \"String url = rublon.auth(\\n  \\\"http://example.com/rublon_transaction_callback\\\", // callback URL\\n  Session.getUser().getId(), // User Id\\n  Session.getUser().getEmail(), // User email\\n  String.format(\\\"Do you confirm transaction no. %s with the amount of %d?\\\", transId, amount),\\n  new JSONObject() {{\\n    put(\\\"transId\\\", transId);\\n    put(RublonAuthParams.FIELD_CONFIRM_TIME_BUFFER, 300); // 5 minutes\\n  }}\\n);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n##Sharing Access\n\nWhen a user's account is protected by Rublon, there is no possibility to login by other people which are knowing the user name and password. But sometimes there is a need to do that, for example two administrators are using the same account to update the news feed on their website.\n\nFor a such cases Rublon provides the Share Access feature. The Rublon user which is associated with the website's account (the host user) can share his access with other Rublon user (the client user). To achieve this, the host user have to enter the client user's email address in the Share Access Widget, which should be visible when displaying the [Rublon GUI](doc:sdk-gui) (if the feature has been activated for the integration).\n\nThe client user will be able to login to the website's account, but by default he won't be able to confirm operation. To enable confirmations for the client user, the host user have to click the \"Enable confirming vulnerable operations\" option on the Share Access Widget.\n\n##Remote Logout\n\nWhen a Rublon user removes his Trusted Devices, Rublon is able to notify all websites associated with this device that user has deleted the device. Websites which implemented the remote logout listeners can logout the user immediately and destroy his session for a security reasons.\n\n###Server-side listener\n\nDeveloper can create a server-side logout listener which is based on the callback URL. Rublon server wants to notify your website about the deleted device will perform a REST request to the callback URL. You have to implement an additional method in the `Rublon2FactorCallback` subclass to handle this action.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<?\\nclass MyCallback extends Rublon2FactorCallback {\\n\\n    /**\\n     * Delete sessions with given userId and deviceId.\\n     * \\n     * :::at:::see Rublon2FactorCallback::handleLogout()\\n     */\\n    protected function handleLogout($userId, $deviceId) {\\n        global $db;\\n\\n        // Delete user's session from database:\\n        $sql = \\\"DELETE FROM sessions WHERE user_id = %d AND (rublon_device_id = %d OR rublon_device_id IS NULL)\\\";\\n        $db->query($sql, $userId, $deviceId);\\n\\n    }\\n\\n}\\n\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"class Callback : Rublon2FactorCallback \\n{\\n    protected override string getState() \\n    {\\n        return Request.Params[PARAMETER_STATE];\\n    }\\n    \\n    protected override string getAccessToken() \\n    {\\n        return Request.Params[PARAMETER_ACCESS_TOKEN];\\n    }\\n    \\n    protected override void handleCancel() \\n    {\\n        Response.Redirect(\\\"/Login\\\");\\n    }\\n    \\n    protected override void handleError() \\n    {\\n        Response.Redirect(\\\"/Login/?msg=rublon-error\\\");\\n    }\\n    \\n    protected override void userAuthenticated(string userId) \\n    {\\n        Session[\\\"loggedUsed\\\"] = User.GetById(userId);\\n        Response.Redirect(\\\"/\\\");\\n    }\\n    \\n    protected override override void handleLogout()\\n    {\\n        RemoteLogout logout = new RemoteLogout(rublon);\\n        logout.Handle();\\n    }    \\n}\\n\\nclass RemoteLogout : RemoteLogoutHandler \\n{\\n    protected override string getHTTPRequestPost()\\n    {\\n        return Request.Content;\\n    }\\n\\n    protected override string getHTTPRequestHeader(string name)\\n    {\\n        return Request.Headers[name];\\n    }\\n\\n    protected override void setHTTPResponseBody(string body)\\n    {\\n        Response.Write(body);\\n    }\\n\\n    protected override void logoutUser(string userId, int deviceId)\\n    {\\n        // remove user's session\\n    }\\n}\",\n      \"language\": \"csharp\",\n      \"name\": \".NET\"\n    },\n    {\n      \"code\": \"class Callback extends Rublon2FactorCallback {\\n  public String getState() {\\n    return HttpServer.getRequestHandler().getParam(PARAMETER_STATE);\\n  }\\n  public String getAccessToken() {\\n    return HttpServer.getRequestHandler().getParam(PARAMETER_ACCESS_TOKEN);\\n  }\\n  protected void handleCancel() {\\n    HttpServer.sendHeader(\\\"Location\\\", \\\"/login\\\");\\n  }\\n  protected void handleError() {\\n    HttpServer.sendHeader(\\\"Location\\\", \\\"/login?msg=rublon-error\\\");\\n  }\\n  protected void userAuthenticated(String userId) {\\n    Session.setUser(User.getById(userId));\\n    HttpServer.sendHeader(\\\"Location\\\", \\\"/dashboard\\\");\\n  }\\n\\n  protected void handleLogout() {\\n    MyRemoteLogout logout = new MyRemoteLogout(getRublon());\\n    logout.handle();\\n  }\\n}\\n\\nclass MyRemoteLogout extends RemoteLogoutHandler {\\n    \\n  protected String getHTTPRequestPOSTBody() {\\n    return HttpServer.getRequest().getPostBody();\\n  }\\n\\n  protected String getHTTPRequestHeader(String name) {\\n    return HttpServer.getRequest().getHeader(name).first();\\n  }\\n\\n  protected void setHTTPResponseBody(String body) {\\n    HttpServer.setResponse(body);\\n  }\\n\\n  protected void logoutUser(String userId, int deviceId) {\\n    // Remove the session record from the database:\\n    Database.query(\\\"DELETE FROM session WHERE user_id = %s AND (rublon_device_id = %d OR rublon_device_id IS NULL)\\\",\\n                   userId, deviceId);\\n  }\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nAs you can see, the user's session have to be associated with the device ID. This value can be obtained in the callback's $successHandler, as well as the Rublon user's profile ID which can be also handy:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<?\\n$callback = new Rublon2FactorCallback($rublon);\\n$callback->call(\\n    $successHandler = function($userId, Rublon2FactorCallback $callback) {\\n        // The user is finally logged in\\n        $_SESSION[\\\"user\\\"] = $userId;\\n\\n        // Obtain the device ID:\\n        $deviceId = $callback->getCredentials()->getDeviceId();\\n\\n        // Obtain the Rublon user's profile ID:\\n        $profileId = $callback->getCredentials()->getProfileId();\\n\\n    },\\n    $cancelHandler = function(Rublon2FactorCallback $callback) {\\n        // Cancel the authentication process\\n        header(\\\"Location: /login\\\");\\n        exit;\\n    }\\n);\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"protected void userAuthenticated(String userId) \\n{\\n    // The user is finally logged in\\n    Session[\\\"loggedUsed\\\"] = User.GetById(userId);\\n\\n    // Obtain the device ID:\\n    string deviceId = credentials.GetDeviceId();\\n    Session[\\\"deviceId\\\"] = deviceId;\\n\\n    // Obtain the Rublon user's profile ID:\\n    string profileId = credentials.GetProfileId();\\n    Session[\\\"profileId\\\"] = profileId;\\n\\n    Response.Redirect(\\\"/\\\");\\n}\",\n      \"language\": \"csharp\",\n      \"name\": \".NET\"\n    },\n    {\n      \"code\": \"protected void userAuthenticated(String userId) {\\n  // The user is finally logged in\\n  Session.setUser(User.getById(userId));\\n\\n  // Obtain the device ID:\\n  String deviceId = getCredentials().getDeviceId();\\n  Session.set(\\\"rublon_device_id\\\", deviceId);\\n\\n  // Obtain the Rublon user's profile ID:\\n  String profileId = getCredentials().getProfileId();\\n  Session.set(\\\"rublon_profile_id\\\", profileId);\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n###Browser-side listener\n\nDeveloper can add a browser-side logout listener which will listen the Rublon server by using the JavaScript long-pool request.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Please do not use the browser-side listener as a default - do always use the server-side remote logout listeners. The browser-side listener is not the best way to logout user, because he may close the browser earlier or disable JavaScript and then won't be logged-out. However this way provides a good user-experience, because the user is logged out immediately.\"\n}\n[/block]\n\nTo enable the browser-side logout listener, embed the Rublon consumer script on every page in your website:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<?\\necho new RublonConsumerScript($rublon, $userId, $userEmail, $logoutListener = true);\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"ConsumerScript script = new ConsumerScript(rublon, userId, userEmail, /* logoutListener = */ true);\\nResponse.Write(script.ToString());\",\n      \"language\": \"csharp\",\n      \"name\": \".NET\"\n    },\n    {\n      \"code\": \"ConsumerScript script = new ConsumerScript(rublon, userId, userEmail, /* logoutListener = */ true);\\nHttpServer.setResponse(script.toString());\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nAlso you have to provide the JavaScript function which will actually logout the user:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<script type=\\\"text/javascript\\\">\\nfunction RublonLogoutCallback() {\\n    location.href = \\\"/logout\\\";\\n}\\n</script>\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n###Checking the user's Trusted Device status\n\nDeveloper can also use cron to check the user's Trusted Device status for active user's session and delete it when the Trusted Device has been removed.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Please notice that not every user will create a Trusted Device when login to your website.\"\n}\n[/block]\nTo check the user's device status perform the following:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<?\\n$client = new RublonAPICheckUserDevice($rublon, $profileId, $deviceId);\\n$client->perform();\\n$isActive = $client->isDeviceActive();\",\n      \"language\": \"php\"\n    },\n    {\n      \"code\": \"CheckUserDevice client = new CheckUserDevice(rublon, profileId, deviceId);\\nclient.Perform();\\nbool isActive = client.IsDeviceActive();\",\n      \"language\": \"csharp\",\n      \"name\": \".NET\"\n    },\n    {\n      \"code\": \"CheckUserDevice client = new CheckUserDevice(rublon, profileId, deviceId);\\nclient.perform();\\nboolean isActive = client.isDeviceActive();\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nThe `profileId` value you can obtain in the callback's `successHandler` function (PHP) or `userAuthenticated()` method (Java, .NET)","excerpt":"","slug":"sdk-business-level-features","type":"basic","title":"Business level features"}

Business level features


##Getting list of active features Developer can obtain the list of active features for current integration using the following code. [block:code] { "codes": [ { "code": "<?\ntry {\n $client = new RublonAPIGetAvailableFeatures($rublon); // Pass the Rublon2Factor instance.\n $client->perform();\n\n // Here is the list of features:\n $features = $client->getFeatures();\n\n // You can check a signle feature:\n $isRemoteLogoutAvailable = !empty($features[RublonAPIGetAvailableFeatures::FEATURE_REMOTE_LOGOUT]);\n\n} catch (RublonException $e) {\n die($e->getMessage());\n}", "language": "php" }, { "code": "try \n{\n GetAvailableFeatures client = new GetAvailableFeatures(rublon); // Pass the Rublon2Factor instance.\n client.Perform();\n\n // Here is the list of features:\n JObject features = client.GetFeatures();\n\n // You can check a signle feature:\n bool isRemoteLogoutAvailable = features.Value<bool>(GetAvailableFeatures.FEATURE_REMOTE_LOGOUT);\n} \ncatch (RublonException ex) \n{\n // handle errors\n}", "language": "csharp", "name": ".NET" }, { "code": "try {\n\n GetAvailableFeatures client = new GetAvailableFeatures(rublon); // Pass the Rublon2Factor instance.\n client.perform();\n\n // Here is the list of features:\n JSONObject features = client.getFeatures();\n\n // You can check a signle feature:\n boolean isRemoteLogoutAvailable = features.optBoolean(GetAvailableFeatures.FEATURE_REMOTE_LOGOUT, false);\n\n} catch (RublonException e) {\n // handle errors\n}", "language": "java" } ] } [/block] ##Confirmations The [Secure transaction confirmation](doc:sdk-secure-transaction-confirmation) described in this document is an extra feature. ##Force mobile app Developer can force users to authenticate by Rublon mobile app and deny access to users that are using the Email2FA. This will increase the security level, but also requires users to own a smartphone and install the Rublon application. To achieve this you have to pass the additional parameter in the `consumerParams` array during the initiation of the authentication process: [block:code] { "codes": [ { "code": "<?\n$url = $rublon->auth(\n $callbackUrl = \"http://example.com/rublon_callback.php\",\n $_SESSION[\"user\"][\"id\"], // User Id\n $_SESSION[\"user\"][\"email\"], // User email\n $params = array(\n **RublonAuthParams::FIELD_FORCE_MOBILE_APP => true,**\n )\n);", "language": "php" }, { "code": "User user = (User)Session[\"loggedUser\"];\nJObject parameters = new JObject();\nparameters.Add(RublonAuthParams.FIELD_FORCE_MOBILE_APP, true);\n \nstring url = rublon.Authorize\n(\n \"http://example.com/RublonCallback\", // callback URL\n user.Id, // User Id\n user.Email, // User email\n parameters\n);", "language": "csharp", "name": ".NET" }, { "code": "String url = rublon.auth(\n \"http://example.com/rublon_callback\", // callback URL\n Session.getUser().getId(), // User Id\n Session.getUser().getEmail(), // User email\n new JSONObject() {{\n **put(RublonAuthParams.FIELD_FORCE_MOBILE_APP, true);**\n }}\n);", "language": "java" } ] } [/block] You can just imagine a lot of use cases for this feature. For example, the Wordpress administrator which have installed the WP plugin (provided by us) can force choosen users' roles to authenticate using Rublon mobile app. ##Ignore Trusted Device You can increase the security level in some cases, for example when user didn't login for last 30 days, by ignoring his Trusted Device during the Rublon authentication. Even if user's Trusted Device exists, he will be forced to scan the QR code. To achieve this you have to pass the additional parameter in the `consumerParams` array during the initiation of the authentication process: [block:code] { "codes": [ { "code": "<?\n$url = $rublon->auth(\n $callbackUrl = \"http://example.com/rublon_callback.php\",\n $_SESSION[\"user\"][\"id\"], // User Id\n $_SESSION[\"user\"][\"email\"], // User email\n $params = array(\n **RublonAuthParams::FIELD_IGNORE_TRUSTED_DEVICE => true,**\n )\n);", "language": "php" }, { "code": "User user = (User)Session[\"loggedUser\"];\nJObject parameters = new JObject();\nparameters.Add(RublonAuthParams.FIELD_IGNORE_TRUSTED_DEVICE, true);\n \nstring url = rublon.Authorize\n(\n \"http://example.com/RublonCallback\", // callback URL\n user.Id, // User Id\n user.Email, // User email\n parameters\n);", "language": "csharp", "name": ".NET" }, { "code": "String url = rublon.auth(\n \"http://example.com/rublon_callback\", // callback URL\n Session.getUser().getId(), // User Id\n Session.getUser().getEmail(), // User email\n new JSONObject() {{\n **put(RublonAuthParams.FIELD_IGNORE_TRUSTED_DEVICE, true);**\n }}\n);", "language": "java" } ] } [/block] ##Buffered confirmation If you want to make life easier for your users and don't need extra high security level when users perform the multiple confirmations in a small amount of time, you can use the buffered confirmations feature. User will be required to confirm the first confirmation using the Rublon mobile app or clicking the confirmation link sent to his email address (when using Email2FA). Developer determines a time buffer withing the next user's confirmation will be accepted immediately, without the need to use the mobile app or checking the email. The only requirement is that the user's Trusted Device has to be present before performing the confirmation. Without a Trusted Device every transaction have to be confirmed manually. The following code shows how to determine the time buffer (in seconds) during the confirmation transaction initiation: [block:code] { "codes": [ { "code": "<?\n$url = $rublon->confirm(\n $callbackUrl = \"http://example.com/rublon_transaction_confirm.php\",\n $user[\"id\"], // User Id\n $user[\"email\"], // User email\n $msg = sprintf(\"Do you confirm transaction no. %d with the amount of %d?\", $transId, $amount),\n $params = array(\n \"transId\" => $transId, // Additional transaction parameters\n RublonAuthParams::FIELD_CONFIRM_TIME_BUFFER => 300, // 5 minutes\n )\n);", "language": "php" }, { "code": "User user = (User)Session[\"loggedUser\"];\nJObject parameters = new JObject();\nparameters.Add(\"transId\", transId); \nparameters.Add(RublonAuthParams.FIELD_CONFIRM_TIME_BUFFER, 300); // 5 minutes\n\nstring url = rublon.Confirm\n(\n \"http://example.com/TransactionConfirmCallback\", // callback URL\n user.Id, // User Id\n user.Email, // User email\n string.format(\"Do you confirm transaction no. {0} with the amount of {1}?\", transId, amount),\n parameters\n);", "language": "csharp", "name": ".NET" }, { "code": "String url = rublon.auth(\n \"http://example.com/rublon_transaction_callback\", // callback URL\n Session.getUser().getId(), // User Id\n Session.getUser().getEmail(), // User email\n String.format(\"Do you confirm transaction no. %s with the amount of %d?\", transId, amount),\n new JSONObject() {{\n put(\"transId\", transId);\n put(RublonAuthParams.FIELD_CONFIRM_TIME_BUFFER, 300); // 5 minutes\n }}\n);", "language": "java" } ] } [/block] ##Sharing Access When a user's account is protected by Rublon, there is no possibility to login by other people which are knowing the user name and password. But sometimes there is a need to do that, for example two administrators are using the same account to update the news feed on their website. For a such cases Rublon provides the Share Access feature. The Rublon user which is associated with the website's account (the host user) can share his access with other Rublon user (the client user). To achieve this, the host user have to enter the client user's email address in the Share Access Widget, which should be visible when displaying the [Rublon GUI](doc:sdk-gui) (if the feature has been activated for the integration). The client user will be able to login to the website's account, but by default he won't be able to confirm operation. To enable confirmations for the client user, the host user have to click the "Enable confirming vulnerable operations" option on the Share Access Widget. ##Remote Logout When a Rublon user removes his Trusted Devices, Rublon is able to notify all websites associated with this device that user has deleted the device. Websites which implemented the remote logout listeners can logout the user immediately and destroy his session for a security reasons. ###Server-side listener Developer can create a server-side logout listener which is based on the callback URL. Rublon server wants to notify your website about the deleted device will perform a REST request to the callback URL. You have to implement an additional method in the `Rublon2FactorCallback` subclass to handle this action. [block:code] { "codes": [ { "code": "<?\nclass MyCallback extends Rublon2FactorCallback {\n\n /**\n * Delete sessions with given userId and deviceId.\n * \n * @see Rublon2FactorCallback::handleLogout()\n */\n protected function handleLogout($userId, $deviceId) {\n global $db;\n\n // Delete user's session from database:\n $sql = \"DELETE FROM sessions WHERE user_id = %d AND (rublon_device_id = %d OR rublon_device_id IS NULL)\";\n $db->query($sql, $userId, $deviceId);\n\n }\n\n}\n", "language": "php" }, { "code": "class Callback : Rublon2FactorCallback \n{\n protected override string getState() \n {\n return Request.Params[PARAMETER_STATE];\n }\n \n protected override string getAccessToken() \n {\n return Request.Params[PARAMETER_ACCESS_TOKEN];\n }\n \n protected override void handleCancel() \n {\n Response.Redirect(\"/Login\");\n }\n \n protected override void handleError() \n {\n Response.Redirect(\"/Login/?msg=rublon-error\");\n }\n \n protected override void userAuthenticated(string userId) \n {\n Session[\"loggedUsed\"] = User.GetById(userId);\n Response.Redirect(\"/\");\n }\n \n protected override override void handleLogout()\n {\n RemoteLogout logout = new RemoteLogout(rublon);\n logout.Handle();\n } \n}\n\nclass RemoteLogout : RemoteLogoutHandler \n{\n protected override string getHTTPRequestPost()\n {\n return Request.Content;\n }\n\n protected override string getHTTPRequestHeader(string name)\n {\n return Request.Headers[name];\n }\n\n protected override void setHTTPResponseBody(string body)\n {\n Response.Write(body);\n }\n\n protected override void logoutUser(string userId, int deviceId)\n {\n // remove user's session\n }\n}", "language": "csharp", "name": ".NET" }, { "code": "class Callback extends Rublon2FactorCallback {\n public String getState() {\n return HttpServer.getRequestHandler().getParam(PARAMETER_STATE);\n }\n public String getAccessToken() {\n return HttpServer.getRequestHandler().getParam(PARAMETER_ACCESS_TOKEN);\n }\n protected void handleCancel() {\n HttpServer.sendHeader(\"Location\", \"/login\");\n }\n protected void handleError() {\n HttpServer.sendHeader(\"Location\", \"/login?msg=rublon-error\");\n }\n protected void userAuthenticated(String userId) {\n Session.setUser(User.getById(userId));\n HttpServer.sendHeader(\"Location\", \"/dashboard\");\n }\n\n protected void handleLogout() {\n MyRemoteLogout logout = new MyRemoteLogout(getRublon());\n logout.handle();\n }\n}\n\nclass MyRemoteLogout extends RemoteLogoutHandler {\n \n protected String getHTTPRequestPOSTBody() {\n return HttpServer.getRequest().getPostBody();\n }\n\n protected String getHTTPRequestHeader(String name) {\n return HttpServer.getRequest().getHeader(name).first();\n }\n\n protected void setHTTPResponseBody(String body) {\n HttpServer.setResponse(body);\n }\n\n protected void logoutUser(String userId, int deviceId) {\n // Remove the session record from the database:\n Database.query(\"DELETE FROM session WHERE user_id = %s AND (rublon_device_id = %d OR rublon_device_id IS NULL)\",\n userId, deviceId);\n }\n}", "language": "java" } ] } [/block] As you can see, the user's session have to be associated with the device ID. This value can be obtained in the callback's $successHandler, as well as the Rublon user's profile ID which can be also handy: [block:code] { "codes": [ { "code": "<?\n$callback = new Rublon2FactorCallback($rublon);\n$callback->call(\n $successHandler = function($userId, Rublon2FactorCallback $callback) {\n // The user is finally logged in\n $_SESSION[\"user\"] = $userId;\n\n // Obtain the device ID:\n $deviceId = $callback->getCredentials()->getDeviceId();\n\n // Obtain the Rublon user's profile ID:\n $profileId = $callback->getCredentials()->getProfileId();\n\n },\n $cancelHandler = function(Rublon2FactorCallback $callback) {\n // Cancel the authentication process\n header(\"Location: /login\");\n exit;\n }\n);", "language": "php" }, { "code": "protected void userAuthenticated(String userId) \n{\n // The user is finally logged in\n Session[\"loggedUsed\"] = User.GetById(userId);\n\n // Obtain the device ID:\n string deviceId = credentials.GetDeviceId();\n Session[\"deviceId\"] = deviceId;\n\n // Obtain the Rublon user's profile ID:\n string profileId = credentials.GetProfileId();\n Session[\"profileId\"] = profileId;\n\n Response.Redirect(\"/\");\n}", "language": "csharp", "name": ".NET" }, { "code": "protected void userAuthenticated(String userId) {\n // The user is finally logged in\n Session.setUser(User.getById(userId));\n\n // Obtain the device ID:\n String deviceId = getCredentials().getDeviceId();\n Session.set(\"rublon_device_id\", deviceId);\n\n // Obtain the Rublon user's profile ID:\n String profileId = getCredentials().getProfileId();\n Session.set(\"rublon_profile_id\", profileId);\n}", "language": "java" } ] } [/block] ###Browser-side listener Developer can add a browser-side logout listener which will listen the Rublon server by using the JavaScript long-pool request. [block:callout] { "type": "info", "body": "Please do not use the browser-side listener as a default - do always use the server-side remote logout listeners. The browser-side listener is not the best way to logout user, because he may close the browser earlier or disable JavaScript and then won't be logged-out. However this way provides a good user-experience, because the user is logged out immediately." } [/block] To enable the browser-side logout listener, embed the Rublon consumer script on every page in your website: [block:code] { "codes": [ { "code": "<?\necho new RublonConsumerScript($rublon, $userId, $userEmail, $logoutListener = true);", "language": "php" }, { "code": "ConsumerScript script = new ConsumerScript(rublon, userId, userEmail, /* logoutListener = */ true);\nResponse.Write(script.ToString());", "language": "csharp", "name": ".NET" }, { "code": "ConsumerScript script = new ConsumerScript(rublon, userId, userEmail, /* logoutListener = */ true);\nHttpServer.setResponse(script.toString());", "language": "java" } ] } [/block] Also you have to provide the JavaScript function which will actually logout the user: [block:code] { "codes": [ { "code": "<script type=\"text/javascript\">\nfunction RublonLogoutCallback() {\n location.href = \"/logout\";\n}\n</script>", "language": "javascript" } ] } [/block] ###Checking the user's Trusted Device status Developer can also use cron to check the user's Trusted Device status for active user's session and delete it when the Trusted Device has been removed. [block:callout] { "type": "info", "body": "Please notice that not every user will create a Trusted Device when login to your website." } [/block] To check the user's device status perform the following: [block:code] { "codes": [ { "code": "<?\n$client = new RublonAPICheckUserDevice($rublon, $profileId, $deviceId);\n$client->perform();\n$isActive = $client->isDeviceActive();", "language": "php" }, { "code": "CheckUserDevice client = new CheckUserDevice(rublon, profileId, deviceId);\nclient.Perform();\nbool isActive = client.IsDeviceActive();", "language": "csharp", "name": ".NET" }, { "code": "CheckUserDevice client = new CheckUserDevice(rublon, profileId, deviceId);\nclient.perform();\nboolean isActive = client.isDeviceActive();", "language": "java" } ] } [/block] The `profileId` value you can obtain in the callback's `successHandler` function (PHP) or `userAuthenticated()` method (Java, .NET)