TFS 2015 REST API Authentication

vikkee picture vikkee · Mar 17, 2016 · Viewed 13.8k times · Source

We are trying to invoke the TFS 2015 REST API's from a web-page using Javascript and have a challenge in establishing valid authentication with the TFS server.

We do not know how to generate a personal access tokens or an OAuth access tokens. The instruction below seem to apply more toward VSO than on-premise TFS. https://www.visualstudio.com/en-us/integrate/get-started/rest/basics

How can I generate an authentication key/token?

UPDATE: As on Mar 2017, the latest release of On-Prem TFS supports creating personal access tokens for all users. Using the below javascript code by @Elmar you can make requests to update, edit TFS workitems from REST API.

Answer

Elmar picture Elmar · Mar 18, 2016

The OAuth mechanism is used against the VSO api at the time of writing this as you've seemingly identified. official docs for VSO OAuth tokens here.

For on-prem however, the following is required:

Via a javascript client (note I'm using jquery for the ajax request here)

Since alternative creds or token based auth isn't available on-prem to match current vso implementation; You can consider the following approach: If you have admin permissions on the TFS app tier, you can configure basic authentication for the tfs application in IIS, and set the default domain.

enabling basic auth and setting domain

And then invoke as follows:

var self = this;
        self.tasksURI = 'https://<SERVER>/tfs/<COLLECTION>/<PROJECT>/_apis/build/builds?api-version=2.0';
        self.username = "<USERNAME>"; //basic username so no domain here.
        self.password = "<PASSWORD>";

        self.ajax = function (uri, method, data) {
            var request = {
                url: uri,
                type: method,
                contentType: "application/json",
                accepts: "application/json",
                cache: false,
                dataType: 'json',
                data: JSON.stringify(data),
                beforeSend: function (xhr) {
                    xhr.setRequestHeader("Authorization", "Basic " + btoa(self.username + ":" + self.password));
                },
                error: function (jqXHR) {
                    console.log("ajax error " + jqXHR.status);
                }
            };
            return $.ajax(request);
        }

        self.ajax(self.tasksURI, 'GET').done(function (data) {

            alert(data);

        });

IMPORTANT NOTE! : If you enable basic auth you really should configure your site to use https too or your credentials will be sent in clear text (as indicated in the warning seen -> top right of the image above).


Via a .NET client

In on-prem (currently rtm'd: 2015 update 1) the api is generally gated/fenced off with NTLM, meaning a pre-flight request is made, 401 returned from server to challenge for auth, in this case, setting the request Credential as follows allows the request to auth against the server once the preflight challenge is received. To accommodate the challenge you can do this:

request.Credentials = new NetworkCredential(this.UserName, this.Password);
//you may want to specify a domain too

If you've enabled basic auth for tfs on prem you can attempt authenticating as follows, this pattern matches the mechanism used when invoking vso after enabling alternative credentials in the ui:

request.Headers[HttpRequestHeader.Authorization] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(this.UserName + ":" + this.Password));

Note: In some code I modified a few weeks ago; support for both VSO and on-prem was required so I used the two patterns above to deal with the specific scenario.