Search code examples
autodesk-forgeautodesk-viewerautodesk-model-derivative

Autodesk Forge Viewer: CORS blocked, Same Origin Policy disallows reading the remote resource


I have the following code:

const initOpts = {
  env: 'AutodeskProduction',
  // getAccessToken: onTokenRequest,
  accessToken: forgeAuthToken,
  api: 'derivativeV2',
};

Autodesk.Viewing.Initializer(initOpts, handleViewerInit);

And update the viewer div with the following (React-based, this part loads the expected div with the loader, etc):

const viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerRef.current)
const err = viewer.start();

const documentId = `urn:dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6YnVja2V0LTk5OC8xMzQ0NDY0NjEyLmR3Zw`;
console.log('documentId', documentId);

Autodesk.Viewing.Document.load(documentId, handleDocumentLoadSuccess, handleDocumentLoadError);

I've simplified the code a bit, as it uses React hooks etc, but regardless, the Autodesk.Viewing.Document.load method calls the error callback, which reports 401 with the following developerMessage: "Access token provided is invalid or expired."


On generating the access token, I've used the method below:

forgeAuthToken is received from a backend route, generated with the following:

const forgeRefreshToken = true;
const {
  FORGE_CLIENT_ID = "...",
  FORGE_CLIENT_SECRET = "...",
} = process.env;
const forgeScopes = [
  'data:read',
  'data:write',
  'bucket:create',
  'bucket:read',
  'bucket:update',
  'bucket:delete',
  'viewables:read',
];
const tokenAuth = new ForgeApis.AuthClientTwoLegged(
  FORGE_CLIENT_ID,
  FORGE_CLIENT_SECRET,
  forgeScopes,
  forgeRefreshToken,
);
const token = await tokenAuth.authenticate();

It's of the form:

{ 
  access_token: "<token>",
  token_type: "Bearer",
  expires_in: 3599,
  expires_at: Date Mon Sep 07 2020 11:59:42 GMT+0100 (British Summer Time)
}

I've tried with more and less scopes to confirm that's not the issue, as I know it requires the viewables:read scope, but was unsure if the other scopes might affect that.

Note that I have replaced my development URL with "$DEVELOPMENT_URL" as I'm not following best security practices yet, but it's an EC2 public URL of the format http://ec2-<public-ip>.eu-west-2.compute.amazonaws.com:<port>

This is the same URL I have configured as both the callback and website URL on the Forge app control panel.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at 
https://developer.api.autodesk.com/derivativeservice/v2/manifest/adsk.objects%3Aos.object%3Aasdfqwerff%2FLON-BH-NBH-B1-1020.dwg?domain="$DEVELOPMENT_URL". 
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

What am I doing incorrectly? I've followed both this and this, and now I'm out of ideas on what has failed


Bit more information, I've logged Autodesk.Viewing.token (of the form eyJhb...9SkIs), and decoded the JWT access token which gives the following, just to check this wasn't some instance problem with the way I've implemented the viewer's token:

{
  "scope":[
    "data:read",
    "data:write",
    "bucket:create",
    "bucket:read",
    "bucket:update",
    "bucket:delete",
    "viewables:read"
  ],
  "client_id":"<my-client-id>",
  "aud":"https://autodesk.com/aud/jwtexp60",
  "jti":"DJUX42Gdl6mYhbCF7d2iZUjvdmYuzZR5wQ2j2BdtjNhm7eAx4Ai26pBKrNFuTScd",
  "exp":1599479159,
}

So the viewer definitely has the token prior to viewing, which works for creating buckets, uploading objects, etc.


Per request, the headers from the pre-flight OPTIONS

Request headers

OPTIONS /derivativeservice/v2/manifest/dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6ZGFkcy8xMzQ0NDY0NjEyLmR3Zw?domain=http%3A%2F%2Fec2-<public-ip>.eu-west-2.compute.amazonaws.com%3A3000 HTTP/1.1
Host: developer.api.autodesk.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Referer: http://ec2-<public-ip>.eu-west-2.compute.amazonaws.com:3000/
Origin: http://ec2-<public-ip>.eu-west-2.compute.amazonaws.com:3000
Connection: keep-alive

Response headers

HTTP/1.1 200 OK
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.5
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: x-ads-acm-namespace,Accept-Encoding,Content-Encoding,If-Match,x-ads-ul-ctx-oxygen-id,Access-Control-Allow-Origin,If-Modified-Since,Accept,x-ads-ul-ctx-caller-span-id,Expect,x-ads-ul-ctx-source,Content-Range,If-None-Match,x-ads-ul-ctx-workflow-id,x-csrf-token,Content-Length,x-ads-test,Access-Control-Allow-Credentials,Content-Type,x-ads-ul-ctx-client-id,Authorization,x-ads-acm-check-groups,x-ads-acm-groups,x-requested-with,x-ads-acm-scopes,x-ads-ul-ctx-head-span-id,x-ads-ul-ctx-scope,Session-Id,Range,x-ads-force,x-ads-ds-client
Access-Control-Allow-Methods: POST,GET,OPTIONS,HEAD,PUT,DELETE,PATCH
Access-Control-Allow-Origin: http://ec2-<public-ip>.eu-west-2.compute.amazonaws.com:3000
Access-Control-Max-Age: 86400
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Content-Type: text/html
Date: Mon, 07 Sep 2020 12:37:59 GMT
Origin: http://ec2-<public-ip>.eu-west-2.compute.amazonaws.com:3000
Referer: http://ec2-<public-ip>.eu-west-2.compute.amazonaws.com:3000/
Strict-Transport-Security: max-age=31536000; includeSubDomains
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0
Vary: Origin
X-Forwarded-For: 188.214.12.163
X-Forwarded-Port: 443
X-Forwarded-Proto: https
Content-Length: 0
Connection: keep-alive

Solution

  • After re-reading the request headers I noticed the Authorisation header was 'Bearer [object Object]'. I posted the entire credentials object, instead of the access token property. Problem solved!