# Connecting User Accounts

Kloudless provides an OAuth 2.0 flow to authenticate users and provide your application with an access token to use to perform API requests to that user's Account.

In addition, your application's confidential API Key can be used to access data for any Account connected to your application.

# Using the Authenticator

In this article, we'll use Kloudless' Authenticator JS, an open-source library that prompts a user to grant access to a given cloud service. We will set up a basic web server to render a page that launches the Authenticator, which completes the OAuth flow on the client-side via a pop-up. You can find detailed documentation on the Authenticator on its GitHub page here.

# Web server

In this example, our web server's purpose is to enable a user to save arbitrary text to a text file in their cloud storage account via our app.

# HTML page

The HTML form below contains two hidden input fields that must be populated with the ID of the cloud storage account, and a bearer token to access it, so that our backend server can perform the API request to upload the file.

<form action="/post" method="post">
    <input type="hidden" name="access_token" id="access_token" value="">
    <input type="hidden" name="account_id" id="account_id" value="">
    <div>
        <input type="text" name="fileName" placeholder="file-name.txt">
    </div>
    <div>
        <textarea name="file_body" rows="7">File text here.</textarea>
    </div>
    <div>
        <button id="upload" type="submit" disabled>Create and upload file</button>
    </div>
</form>

To authenticate the user, include a script tag on the page that sources the Authenticator JS library as documented in the Authenticator's README.

<script type="text/javascript"
src="https://static-cdn.kloudless.com/p/platform/sdk/kloudless.authenticator.js"></script>

This exposes a global Kloudless object that contains the method Kloudless.auth.authenticator, which we'll use to trigger an authentication pop-up for the end-user.

# JavaScript

In the Kloudless.auth.authenticator call below:

  • $element is the DOM element to click to launch the pop-up, or a jQuery object representing one.
  • config includes additional query parameters to include in the OAuth flow. At a minimum, this must include the Kloudless application ID as the OAuth Client ID. It can also include a scope, as documented in the Scopes article, to display a subset of services.
  • callback is a JS callback method that receives the results of the OAuth flow.
$(document).ready(() => {
    const config = {
        'client_id': '[INSERT YOUR CLIENT ID HERE]',
        'scope': 'storage',
    };

    // Assumes a button with ID "auth" on the page to launch the pop-up.
    var $element = $("#auth");

    let auth = Kloudless.auth.authenticator($element, config, callback);
});

The callback method above should handle errors as well as successful responses.

let callback = function (result) {
    if (result.error) {
        console.log('An error occurred:', result.error);
        return;
    }

    $("#account_id").val(result.account.id);
    $("#access_token").val(result.access_token);
    $("#upload").prop('disabled', false);
};

The JS should now look like below.

let callback = function (result) {
    if (result.error) {
        console.log('An error occurred:', result.error);
        return;
    }

    $("#account_id").val(result.account.id);
    $("#access_token").val(result.access_token);
    $("#upload").prop('disabled', false);
};

$(document).ready(() => {
    const config = {
        'client_id': '[INSERT YOUR CLIENT ID HERE]',
        'scope': 'storage',
    };

    // Assumes a button with ID "auth" on the page to launch the pop-up.
    var $element = $("#auth");

    let auth = Kloudless.auth.authenticator($element, config, callback);
});

We now have all the data in need to send to our server-side code to make an API request. We could also perform the API request via client-side JS if preferbale.

# Verifying Bearer Tokens

The form in the section above sends the server details of an account to upload a text file to. However, before we do so, it is important to verify that our the account was connected using our app, to prevent a Confused Deputy attack, which is when an attacker obtains access tokens through a compromised client or other mechanism and impersonates an end-user, potentially gaining access to privileged content otherwise only accessible to that user.

Use this endpoint on the server-side to verify the token.

Here is an example in a Node server:

axios.get('https://api.kloudless.com/v1/oauth/token', {
    headers: {
        'Authorization': 'Bearer ' + access_token
    }
})
    .then(function(response) {
        if (response.data.client_id === KLOUDLESS_APP_ID) {
            // handle successful verification
        }
        else {
            // handle incorrect app
        }
    })

    .catch(function(error) {
        console.log(error);
    })

Comparing the known client ID to the client ID returned from the GET request is the minimum amount of verification to perform.

With the token now verified, you can make an API call to Kloudless to upload the file to the identified location in the service using this API endpoint.