Sample Console Application using Client Credentials using JavaScript Async

Run Sample Download Sample Source

For applications that do not need to Authenticate the user because the app is not going to access user date, the application can use the OAuth Client Credential Flow. This uses the Client ID and Client Secret that the application developer registered on CodeProject. Because a web page is not a secure place to store client credentials, this is not a recommended method.

Note: The demos use a pre-registered Client ID and Client Secret. For your apps, you will need to register your own. Information about registering a Client ID and Client Secret can be found here.

The following code demonstrates an HTML page that get the first page of the latest Articles and displays the title. The API requests and handling the response is performed asynchronously using JQuery Deferreds. You can see the sample in action by clicking . Clicking on the Get Article button in the sample will request the page of Articles from the server, displaying status along the way.

The sample consists of two files:

The HTML page contains

Index.html listing

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>API example using OAuth2 Client Credentials.</title>
</head>

<body>
    <h2>API example using OAuth2 Client Credentials.</h2>
    <p>
        This sample demonstrates how to use the OAuth2 Client Credentials Flow in JavaScript to 
        obtain an Access Token and how to use the Access Token when calling the CodeProject API.
    </p>
    <input type="button" id="getArticles" value="Get Articles" class="btn" />

    <div id="results"></div>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="app.js"></script>

    <script type="text/javascript">
    $(function () {

        $("#getArticles").click(function () {

            $("#results").html("");

            var data = SampleApp.GetArticles();
            if (data) {

                var html = "<h3>The first " + data.items.length + " of " +
                         +data.pagination.totalItems + " items</h3><ul>";

                for (i = 0; i < data.items.length; i++)
                    html += "<li>" + data.items[i].title + "</li>";

                html += "</ul>";

                $("#results").html(html);
            }
            else {
                $("#results").html("<b>Failed to Load Articles.</b>");
            };
        });
    });
    </script>
</body>
</html>

The JavaScript file create a SampleApp object with one public method GetArticles. This method requests an Access Token, if required, and then request the first page of Articles. Because the JQuery Ajax calls are asynchronous, this method returns a promise which will pass the data returned from the GET /v1/Articles call to the function in the done method for the promise.

apps.js listing

var SampleDataAccess = function () {
    var app = {};
    // CodeProject Test API Key
    var clientApiKey = "JkOnJ9zIQ1vWvP3FvsJVx-3iOnSd-6a-";

    // CodeProject Test Secret
    var clientSecret  = "U_ZHCQackGJHW4-Jn4qfGce6JLV9qAKhJEGahyRHVpeYVWf_r8iSaSt4z6AZn8kC"; 

    var baseUrl       = "https://api.codeproject.com";
    var getTokenUrl   = baseUrl + "/token";
    var generalApiUrl = baseUrl + "/v1/Articles"; // The URL of the API to call

    // The OAuth2 Access Token.
    var appAuthToken; 

    // define the public variables/functions
    app.GetArticles = getArticles;

    // ---------------------------------------------------------------------------------------------------------------------
    // All API calls require an Access Bearer Token to be passed in the Authorization header.
    // This can be obtained from the OAuth2 Server without user credentials using only the 
    // API Key and Secret using the Client Credentials OAuth Flow.
    // Most of the APIs will work with this type of token, however the My API will not and must
    // obtain an Access Token created with any of the other OAuth Flows that include Authentication 
    // of the User.
    function getArticles()
    {
        var dfd = new $.Deferred();

        getAccessTokenByPost()
        .done(function () {
            return $.ajax({
                method:      "get",
                url:         generalApiUrl,
                contentType: "application/json; charset=utf-8",
                headers:     { 'Authorization': 'Bearer ' + appAuthToken }
            })
            .done(function (data) {
                dfd.resolve(data);
            })
            .fail(function () {
                // in a real app, you should check for a 401 and if so delete the Access Token
                // so that it will reload on the next request.
                alert("failed to get articles.");
                dfd.fail();
            });
        });
        return dfd.promise();
    }

    // Checks that there is a saved Access Token.  If one does not exist, it gets one from the
    // OAuth2 Server using the Client Credentials Flow and saves it.
    function getAccessTokenByPost() {
        if (appAuthToken) {
            alert("using saved Access Token");

            // just return a resolved promise.
            return $.Deferred().resolve().promise();
        }
        else {
            var postData = {
                grant_type:    'client_credentials',
                client_id:     clientApiKey,
                client_secret: clientSecret
            };
            return $.post(getTokenUrl, postData, null, 'json')
                    .done(function (data) {
                        alert("got Access Token");
                        appAuthToken = data.access_token;
                    })
                    .fail(function (jqXHR, status, error) {
                        alert("getting Access Token failed.");
                    });
        }
    }
    return app;
}();