Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.

First time visiting? Here are some places to start:
  1. Looking for a certain topic? Check out the categories filter or use Search (upper right).
  2. Need support? Ask a question to our Community Support category.
  3. Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
  4. Be respectful, on topic and if you see a problem, Flag it.

If you would like to contact our Community Manager personally, feel free to send a private message or an email.

Receiving 401 Unauthorized when trying to export an STL or parasolid from Onshape API

Cappie_PomeroyCappie_Pomeroy Member Posts: 14
I have tried both from my local computer and using the API explorer application.  Every other OAuth2Read API call that I've used works as expected both locally and in the API explorer.  I've tried the /parts/d/:did/[wvm]/:wvm/e/:eid/partid/:partid/stl endpoint and the /partstudios/d/:did/[wvm]/:wvm/e/:eid/stl as well as the parasolid ones.  I've used workspace id, version id, and microversion id both locally and in the API explorer.  All result in

`{"message":"Unauthenticated API request", "status":401}`

Any ideas?

Tagged:

Best Answer

Answers

  • Ethan_KEthan_K Member, Onshape Employees Posts: 57
    Hi Cappie,

    This is because our STL call requires following a 307 redirect to the modeling server slated to deliver the tessellation. Upon redirection, you need to re-sign the request with the new parameters, since the request now points to a different resource path, and API key signing integrates the path and query params into the signature. We currently don't handle this correctly in the API explorer, but there is a bug already filed for this. In many clients, the way to support this is to turn off the automated redirect that they provide, and instead handle it manually in a try/catch for 3xx codes that takes the redirect and calculates the new headers for it. You can see an example of this here: https://github.com/onshape-public/onshape-clients/blob/30e9242c5544b35fcb1bb9797334a29443b1d3d8/python/onshape_client/rest.py#L255 . Note that if you are using OAuth, the automated redirect should just work as it doesn't need path-specific signing.

    Hope that helps!
  • Cappie_PomeroyCappie_Pomeroy Member Posts: 14
    Hi Ethan,

    I am using OAuth a simplified version of the python+flask I'm using is
    <code>ONSHAPE_API_URL + '/parts'
    + '/d/' + session['onshape_document']
    + '/m/' + session['onshape_microversion']
    + '/e/' + part_studio_id
    + '/partid/' + part_id
    + '/stl'
    )
    r = requests.get(url, headers)
    print(r.status_code) # 401
    print(r.content) # {"message":"Unauthenticated API request", "status":401}<br><br>import requests<br><br>def get_stl(session, part_studio_id, part_id):<br> headers = { 'Authorization': 'Bearer ' + session['onshape_token'] }<br> url = (<br>
    I'll try catching the 307 and reapplying the headers, but I don't think that the OAuth 'just works' as you said.  Is there something incorrect with this approach?  The other requests that are working use this same scheme so I'm sure the token and header are being set according to Onshape's OAuth implementation.



  • Ethan_KEthan_K Member, Onshape Employees Posts: 57
    Answer ✓
    Hi Cappie,

    This is one of the only endpoints that returns a 307 to a modeling server. My guess is that the HTTP client you are using (requests) is set up not to authenticate on a redirect. That is a reasonable default because they want to be careful about implicitly sending credentials with subsequent requests. However, in this circumstance you have to send the credentials in or else you will correctly get a 401. You can verify whether or not your request has the appropriate headers by printing the headers out that were sent over the wire... see here for how to do that: https://stackoverflow.com/questions/20658572/python-requests-print-entire-http-request-raw . In the Onshape client (still in beta) we custom handle the 3xx codes by turning off automatic redirect logic, and handling the redirect directly: https://github.com/onshape-public/onshape-clients/blob/master/python/onshape_client/oas/rest.py#L233 . 

    Hope that helps!
  • Cappie_PomeroyCappie_Pomeroy Member Posts: 14
    edited October 2019
    Thanks so much for your help Ethan!  I got it working using the Session object of the requests library.  https://requests.kennethreitz.org/en/master/user/advanced/#session-objects and setting the Authorization Header on the session level then I made a while loop to attempt get requests until I get something that isn't a redirect status code.
    <div>import requests<br></div><div><br></div><div>def&nbsp;oauth_get_with_redirects(url,&nbsp;token,&nbsp;parameters={}):</div><div>&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;requests.Session()</div><div>&nbsp;&nbsp;&nbsp;&nbsp;headers&nbsp;=&nbsp;{</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'Authorization':&nbsp;'Bearer&nbsp;'&nbsp;+&nbsp;token</div><div>&nbsp;&nbsp;&nbsp;&nbsp;}</div><div>&nbsp;&nbsp;&nbsp;&nbsp;s.headers.update(headers)</div><div>&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;s.get(url,&nbsp;params=parameters,&nbsp;allow_redirects=False)</div><div>&nbsp;&nbsp;&nbsp;&nbsp;while r.is_redirect:</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;s.get(</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r.headers['Location'],&nbsp;params=parameters,</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;allow_redirects=False</div><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)</div><div>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;r</div>

    Also thanks for pointing out the security flaw of passing along headers I will only use this on the endpoints you specified.
  • alan_kalbfleischalan_kalbfleisch Member Posts: 6
    @Ethan_K
    Just a clarification on this answer. Do you need to recalculate the headers for the redirect using the new url, path and queries or should the redirect have the same headers as the initial request?
  • alan_kalbfleischalan_kalbfleisch Member Posts: 6
    @Ethan_K
    Just a clarification on this answer. Do you need to recalculate the headers for the redirect using the new url, path and queries or should the redirect have the same headers as the initial request?
    Nevermind. Got it figured out. You do have to regenerate the headers for the redirect link based on the new url, path and queries. When making the initial request, the "accept" header needs to be "application/vnd.onshape.v1+octet-stream" and on the redirect, the "accept" header needs to be "application/vnd.onshape.v1+json".
Sign In or Register to comment.