JQuery Sample

The CodeProject APIs are HTML services that allow you to retrieve information from CodeProject about many things. This sample will show you how to retrieve your profile information using JQuery.

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.

Calling the API

To call the CodeProject API you will make simple HTTPS requests. Since the current implementation only returns information, all the requests will be made using GET HTTP methods. Note: all requests MUST be made using HTTPS.

The data can be returned in either JSON or XML. This is determined by the Accept header on the request.

To get your profile information you would make a call to a function on your ViewModel similar to

    self.Load = function()
    {
        $.ajax({
            // Make a call to the protected Web API by passing in a Bearer Authorization Header
            method:      'get',
            url:         app.dataModel.userInfoUrl,
            contentType: "application/json; charset=utf-8",
            headers:     { 'Authorization': 'Bearer ' + app.dataModel.getAccessToken() },
            success: function (data) {
                self.id             = data.id;
                self.userName       = data.userName;
                self.displayName    = data.displayName;
                self.avatar         = data.avatar;
                self.email          = data.email;
                self.htmlEmails     = data.htmlEmails;
                self.country        = data.country;
                self.birthday       = data.birthday;
                self.homePage       = data.homePage;
                self.biography      = data.biography.replace(/\r\n/gm, '<br />');
                self.company        = data.company;
                self.jobTitle       = data.jobTitle;

                //self.codeProjectMemberId  = data.codeProjectMemberId)
                //self.twitterName          = data.twitterName;
                //self.googlePlusProfile    = data.googlePlusProfile;
                //self.linkedInProfile      = data.linkedInProfile;

                self.isLoaded       = true;
            }
        });
    }

    return self;
    }

This method is using two functions from a dataModel object:

Obtaining the OAuth2 Access Token

For a client side JavaScript application, your are most likely to want to use the Implicit Grant OAuth flow. This authenticates the User by redirecting to the Authorization Server, in this case api.codeproject.com.

The Authorization Server will, if the user is not already logged in, redirects to the login page to Authenticate the user and get permission to access their information. If the login is successful, the Authorization Server redirects to the url specified in the original redirection. This url must be identical to the Redirection URL specified in the client registration on CodeProject. More about this later.

So, to a page that wants to call the API needs to check if they already have an Access Token, and if not redirect to the Authorization end point on the Authorization Server.

        // determine the url that the Authorization Server will redirect to when is returns the
        // Access Token
        var clientId = '[your client id]';
        var protocol    = window.location.protocol;
        var port        = window.location.port;  // if default (80 or 443) port will be empty string.
        var redirectUri = protocol + '//' + window.location.hostname;
        if (port !== "")
            redirectUri = redirectUri + ':' + port;
        redirectUri += '/';

        if (!app.dataModel.getAccessToken()) {
        // The following code looks for a fragment in the URL to get the access token which will be
        // used to call the protected Web API resource, in this case the root of the web application.
        var fragment = app.common.getFragment();
        if (fragment.access_token) {
            // returning with access token, restore old hash, or at least hide token
            app.dataModel.setAccessToken(fragment.access_token);
            window.location.assign(fragment.state || redirectUrl);
        } else {
            // no token - so bounce to Authorize endpoint in AccountController to sign in or register
            window.location = "/Account/Authorize?client_id=" + encodeURIComponent(clientId) +
                                "&redirect_uri=" + encodeURIComponent(redirectUri) +
                                "&response_type=token&state=" + encodeURIComponent(window.location.href);
    }

This code checks to see if we already have an Access Token. If we do, then just continue on.

If there is no Access Token then check to see if the Access Token is being returned in the URL. This is accomplished by getting the fragment from the URL and parsing it into an object. If there is a fragment with an Access Token then it saves save the Access Token in so that it can be used to populate the Authorization header, and redirects to the page that originally initiated the Authorization flow.

If there is no fragment with an Access Token, then we need to initiate the Authorization flow. This is accomplished by redirecting to the https:///Account/Authorize endpoint with following parameters:

This sample uses the common.js file include with the ASP.NET SPA template to extract and parse the fragment of the URL. It is included here for reference.

// common.js from the ASP.NET SPA Template. 
window.common = (function () {
    var common = {};
    common.getFragment = function getFragment() {
        if (window.location.hash.indexOf("#") === 0) {
            return parseQueryString(window.location.hash.substr(1));
        } else {
            return {};
        }
    };

    function parseQueryString(queryString) {
        var data = {},
            pairs, pair, separatorIndex, escapedKey, escapedValue, key, value;
        if (queryString === null) {
            return data;
        }
        pairs = queryString.split("&");
        for (var i = 0; i < pairs.length; i++) {
            pair = pairs[i];
            separatorIndex = pair.indexOf("=");
            if (separatorIndex === -1) {
                escapedKey = pair;
                escapedValue = null;
            } else {
                escapedKey = pair.substr(0, separatorIndex);
                escapedValue = pair.substr(separatorIndex + 1);
            }
            key = decodeURIComponent(escapedKey);
            value = decodeURIComponent(escapedValue);
            data[key] = value;
        }
        return data;
    }
    return common;
})();

Notes

Persisting the Access Token is not covered here. Possible implementation could use the HTML5 sessionStorage or localStorage.