Fusion Manage Forum
Welcome to Autodesk’s Fusion Manage (formerly Fusion 360 Manage) Forum. Share your knowledge, ask questions, and explore popular Fusion Manage topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

REST API requests using jQuery and Ajax

16 REPLIES 16
SOLVED
Reply
Message 1 of 17
johnny.buccola
24960 Views, 16 Replies

REST API requests using jQuery and Ajax

Hello,

 

I'm trying to set up a basic web portal which displays data retrieved from my tenant.  I can successfuly log in (using html forms I've set up myself), but using the token in subsequent requests does not seem to work! I'm trying to use jQuery.ajax() method -- I've also attempted the vanilla XMLHttpRequest functions, but I get similar errors.

 

function getUserData(token) {
    var url = "https://mytenant.autodeskplm360.net/api/rest/v1/users/current_user";
    console.log(token);
    $.ajax({
        url: url,    
        method: "GET",
        headers: token,
    }).done(function(resp){
        console.log(resp);
    }).fail(function(r){
        console.log("failed");
    });
}

//token successfully received and parsed through earlier code:

var auth = "Cookie: customer=MYTENANT;JSESSIONID=1726BD35893E3AC68DF544448A9FE438.web13"

getUserData(auth);

Does anybody know what I'm doing wrong? I can't find any examples of successful http requests using javascript in the forums (besides this one ) but it does not cover the cookie-header part, which seems to be tripping up my code. See attached image for the error I receive.

 

I should note that instead adding the header as a key/value pair:

 

{"Cookie": token}

makes my browser console yell at me ( "Refused to set unsafe header 'Cookie'")

 

I'm stumped!

 

 

 

16 REPLIES 16
Message 2 of 17

Reading a little on stackexchange, i found that there are certain headers that are not allowed with XMLHttpRequest, and Cookie is one of them..

 

http://stackoverflow.com/questions/17847283/cookie-header-in-phonegap-refused-to-set-unsafe-header-c...

 

I know that .NET and Java are popular, but if you are looking for a javascript example, I started to play with NodeJS code a while back and I documented a simple example - attached.

 

 

 

 

Message 3 of 17

Thanks Tony!

 

After researching this for the better part of a whole day now, it turns out that "Cookie" being impossible to set as a header in most browsers was my true problem... I wonder if Autodesk using this header name intentionally to prevent something? 

 

Anyways, thanks to some help from a JavaScript/web design expert, you can get around this by using the document.cookie method to put the auth token in document cookie headers, as follows:

 

function fusionLogin(email,password) {
    var url = "https://mytenant.autodeskplm360.net/rest/auth/1/login";
    var payload = {
        "userID": email,
        "password": password
    };
    $.ajax({
        url: url,    
        method: "POST",
        data: payload
    }).done(function(resp){
        var cookie1 = "customer="+ resp.customerToken;
        var cookie2 = "JSESSIONID=" + resp.sessionid;
        document.cookie = cookie1;
        document.cookie = cookie2;
        getUserData(); //call second AJAX request to get the data you need
    }).fail(function(r){
        alert("Login Failed");
    });
}

Note that the subsequent $.ajax "GET" request (which will now automatically use the document cookie as a header) must include the option in BOLD for this to work (ripped that from a similar stackoverflow post):

 

function getUserData() {
    var url = "https://mytenant.autodeskplm360.net/api/rest/v1/users/current_user";
    $.ajax({
        url: url,    
        method: "GET",
        xhrFields: {withCredentials:true}
    }).done(function(resp){
        console.log(resp) // logs {user:{...}}
    }).fail(function(r){
        console.log("failed");
    });
}

Anyways, this seems to be working for me at the moment! Thanks again!

Message 4 of 17

On second thought.... this is not entirely working.

 

It occurred to me that this code works ONLY if I'm logged into the tenant on another tab in the same browser session!

 

The second I close the tab with the logged in tenant, the ajax request fails once again.  It turns out that adding the keys to document.cookie does nothing at all -- it was was xhrFields: {withCredentials:true} that allowed this to work, but I'm still screwed if I close the logged-in tab.

 

I'm stumped and don't know a whole lot about what's going on between tabs here... help?

Message 5 of 17

Hi,

 

Forget what I wrote, from documentation of document.cookie, your implementation seems ok by doing twice the document.cookie = 

 

 

You seem to have a small issue with your logic here:

 

        document.cookie = cookie1;
        document.cookie = cookie2;

 

Your document.cookie is first set to cookie1 but gets "overwritten" by cookie2 on you second line.

 

I think you need to concatenate cookie1 and cookie2 together and set document.cookie with the concatenated result. Something like this:

 

        document.cookie = cookie1 + ";" + cookie2;

 



Dany Poudrier

PLM Product Manager
Message 6 of 17

Hi,

 

From your comments, it seems that the login may not even be successful...

 

Can you check the resp.authStatus value?  

 

Example login response:

{
    "userid": "bloggsj",
    "sessionid": "A22C16C47EDD06390A45C6F3C4A8A918",
    "customerToken": "MYTENANT",
    "authStatus": {
        "id": "200",
        "description": "LOGIN_OK"
    }
}

 

 That seems to fit the symptoms you are describing (that it only works when you are logged in from another tab)...



Dany Poudrier

PLM Product Manager
Message 7 of 17

I think it is logging in properly, actually.

 

Added console.log(resp.authStatus) in the .done() block, and I get the following in the console:

 

{id: 200, description: "LOGIN_OK"}

I receive a token in the full response as well.

 

Message 8 of 17

I'm concerned that it's a problem with Autodesk choosing the "Cookie" key for their authorization token.  I'm not much of an expert in this stuff, but it seems to me that Autodesk might consider allowing the token in the "Authorization" key as well?

 

 

Because the more I look into this, the more unlikely it seems that I'll be able to make an AJAX request to the API through my browser at all (without logging in on a separate tab, that is):

 

http://stackoverflow.com/questions/17847283/cookie-header-in-phonegap-refused-to-set-unsafe-header-c...

 

http://stackoverflow.com/questions/33143776/ajax-request-refused-to-set-unsafe-header

 

On the other hand I'm surprised nobody else has come across this issue -- is nobody else accessing the Fusion API through their own domain?

Message 9 of 17
gasevsm
in reply to: johnny.buccola

Use the JSESSIONID info from the cookie to make subsequent API calls to PLM.

Martin Gasevski | Fusion 360 Team Product Manager
Message 10 of 17
johnny.buccola
in reply to: gasevsm

Hi Martin,

 

Can you be a little more specific? Maybe a short block of code? I've been trying to add the JSESSIONID to the header in a number of different ways, and they're all failing... 

 

function fusionLogin(email,password) {
    var url = "https://mytenant.autodeskplm360.net/rest/auth/1/login";
    var payload = {
        "userID": email,
        "password": password
    };
    $.ajax({
        url: url,    
        method: "POST",
        data: payload
    }).done(function(resp){
        $('#login-overlay').hide();
        $('#sidenav').removeClass('hidden');
        var cookie1 = "customer="+ resp.customerToken;
        var cookie2 = "JSESSIONID=" + resp.sessionid;
        document.cookie = cookie1; //document.cookie adds cookie1 to document
        document.cookie = cookie2; //document.cookie adds cookie2 to document
        var c = document.cookie; 
        console.log(c); //customer=MYTENANT; JSESSIONID=A015010DE40990EA580202B2CE8A7F47.web14
        console.log(resp.authStatus); //200 OK
        getUserData(); //GET /users/current_user (FAILS)
        getProjectData(); //GET /workspaces/97/items (FAILS)
    }).fail(function(r){
        console.log(r);
        alert("Login Failed");
    });
}
Message 11 of 17

Hi Johnny,

 

Can you try to set another cookie (for testing)?

 

var cookie3 = "token="+ resp.customerToken;
document.cookie = cookie3;

The reason I am asking is that I see in the documentation and during my tests that the endpoint is using also "token" as cookie name.

 

 

Moreover, Have you tried to add the crossDomain flag? 

 

xhrFields: {
    withCredentials: true
},
crossDomain: true,

 



Dany Poudrier

PLM Product Manager
Message 12 of 17

Hey Danny,

 

I did actually notice that myself, and tried it earlier, but it doesn't seem to make a difference. I did add the "crossDomain: true", as you advised (request still fails).

 

It also occurred to me that setting "document.cookie" may not actually be affecting the request header cookie at all. 

 

After clearing the browser cache, and then using the same above code for the AJAX request (with document.cookie = cookie1; document.cookie=cookie2), I checked the failed request again through the chrome debugger:

 

 

Request Headers

Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Cookie:excludeweekends=no
Host:XXXXXX.autodeskplm360.net
Origin:http://localhost:5000
Referer:http://localhost:5000/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/5
37.36

 

As you can see, the authorization cookies actually aren't present in the request after all (not sure what excludeweekends=no is, or how IT got there)... if I log into my tenant on another tab however, and then refresh the request, those cookies are suddenly present, and the request is successful.  It seems like the Fusion server is the only thing that can set a cookie in a request?

 

Message 13 of 17

Hello Johnny,

 

I created a web server and started playing with your code. I included one of our architect to decipher what what your issue.

 

It should have been obvious but I was so close to the tree that I didn't see the forest: What you are asking is cross domain script access to a session cookie.

 

This is something that we do not allow (actually most website don't allow) as it opens a breach for cross-site scripting attacks (XSS).

 

So what you are doing is forbidden for security reasons.

 

The proper way would be to have your server as proxy to get the call from your client and the server will do the call to login and fetch the right information via the REST API of Fusion Lifecycle.

 

This blog post is a good article on why we are not allowing it (we protect via the httponly attribute of the cookie).

 

 

 

 

 

 



Dany Poudrier

PLM Product Manager
Message 14 of 17


@dany.poudrier wrote:

 

 

So what you are doing is forbidden for security reasons.

 

The proper way would be to have your server as proxy to get the call from your client and the server will do the call to login and fetch the right information via the REST API of Fusion Lifecycle. 

 


Awesome... glad you've figured it out!

 

So, specifically, which part of what I'm doing is forbidden? Having my client make the HTTP request? (sorry, I'm pretty new to this whole CORS/XSS thing) I don't fully understand why the API calls work when the cookie is set by logging in on another tab.


Can you maybe provide a bit of pseudo-code to help out with the next step here? I've been using a localhost (and occasionally a firebase.google deoployment) server to test my code, which I sort of assumed was working as a proxy anyhow (clearly I'm way off here).

Message 15 of 17

Hi,

 

Here is the short version of what is happening with cookies:

 

With Browser directly or Postman: 

 

1- Call endpoint to login --> get the response JSESSIONID

2- Set the cookie JSESSIONID in the header and CALL the current_user payload. 

 

This is working because the JSESSIONID is set to httponly so your browser/postman can see and send this cookie.

 

With Javascript

 

1- Call endpoint to login --> get the response JSESSIONID

2- Set the cookie JSESSIONID in the header --> Not allowed in Javascript for CORS security reasons,  Set the JSESSIONID cookie --> the updated cookie will not be sent to Server because it is marked as httponly so implicitly not allowed in javascript for CORS security reasons.

 

 

Unfortunately, using firebase will not help you on this:  What you need is an application server like node.js or Tomcat. Firebase is really nice for "static" files and does not offer any server side customization.

 

The workflow needs to be: your web client calls your web server's endpoint and your web server will call Autodesk Web Server's endpoint to Login and Get info. Your Web server would serve as proxy between your web client and our Web Server.

 

You can see on the forum that most of our customers are using .Net or other "hard software" on premise to access our Web Servers.

 

For your information, we are working on another authentication method that would allow what you are trying to achieve via web client but it is currently planned for early next year.

 

 

 



Dany Poudrier

PLM Product Manager
Message 16 of 17

You're the man, Dany. That's a great summary -- sounds like I need to take a tutorial on HTTP or something. 

 

Anyways, thanks for the help! I know there's lots of other changes to the API coming, so it's good to know that this type of authentication may be available sometime in the near future.  I may look in to Heroku in the meantime.

Message 17 of 17

Hi Johnny,

 

I have perhaps an alternative that you could try. Depending on your use cases it might fit your need. 

 

You are using a web page to access the data, so I guess you enter your username/password in that page.  You are trying to club together the login and get of data with java script.

 

As mentioned, calling the login method with javascript does not store the login cookie.

 

However if you divide your steps into 2 steps, you can achieve what you want.

 

You need to have separate steps:

 

1- Create an HTML form that will login. Because it has 0 javascript, the cookie will stick to the session.

2- Create buttons to get the data and manipulate it using Javascript. (using the xhrFields: {withCredentials: true} ).

 

Here is a form that I used to login.  Note that on press of the submit, the target redirect to a dummy IFrame. You could also do target="_blank" to send to another tab. After login you can call any of Fusion Lifecycle endpoint.

 

Using  enctype='application/json' makes the payload json format so it is what the server expects and method=POST is also what server expects. 

 

 

<form name = "formlogin" id="formlogin" action="https://previewcpdmadskpo.autodeskplm360.net/rest/auth/1/login" enctype='application/json' method="POST" target="responseframe">

  Username:<br>
  <input type="text" name="userID"><br>
  Password:<br>
  <input type="text" name="password">

  <input type="submit" value="Submit">
	
</form>

<iframe width="0" height="0" border="0" name="responseframe" id="responseframe"></iframe>

 

I still believe it is better that you handle the information on the server, but has you wait for our new APIs to be available, you can have fun with this.

 

 



Dany Poudrier

PLM Product Manager

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report